Класс Delphi в С#
Я знаю, что этот вопрос был задан раньше, но я еще должен увидеть короткий, ясный ответ, поэтому я надеюсь, что они не удалят этот вопрос, и теперь я получу четкий ответ:
В настоящее время я работаю в С# 5.0;.NET 4.5; VS 2012. Я в основном парень из Delphi, хотя я сделал много с С#.
В Delphi я написал сотни фабрик классов, которые используют следующий вид дизайна (МНОГО УПРОЩЕННОЕ ЗДЕСЬ):
unit uFactory;
interface
type
TClassofMyClass = class of TMyClass;
TFactoryDict = TDictionary<TMyEnum, TClassofMyClass>;
var fDict:TFactoryDict;
implementation
procedure initDict;
begin
fDict:=TFactoryDict.create;
fDict.add(myEnum1, TMyClass1);
fDict.add(myEnum2, TMyClass2);
fDict.add(myEnum3, TMyClass3);
end;
function Factory(const aEnum: TMyEnum): TMyClass;
var
ClassofMyClass: TClassofMyClass;
begin
if fDict.TryGetValue(aEnum, ClassofMyClass) then
result := ClassofMyClass.Create(aParam);
end;
end.
Теперь: КАК я делаю что-то подобное в С#?! Кажется, в С# есть класс НЕТ. Я что-то упускаю? Как я могу реализовать этот тип класса factory просто и элегантно в С#? Этот дизайн может быть реализован и на Python - почему С# будет хуже?!
Ответы
Ответ 1
Вы можете использовать Type:
Dictionary<ClassEnum, Type> TypeDictionary = new Dictionary<ClassEnum, Type>();
public void InitDictionary()
{
TypeDictionary.Add(ClassEnum.FirstClass, typeof(FirstClass));
//etc...
}
public object Factory(ClassEnum type)
{
if (!TypeDictionary.ContainsKey(type))
return null;
var constructor = TypeDictionary[type].GetConstructor(....);
return constructor.Invoke(....);
}
Но я думаю, вы должны использовать общий метод:
public T Factory<T>(): where T is MyBaseClass
{
var type = typeof(T);
var constructor = type.GetConstructor(....);
return constructor.Invoke(....) as T;
}
Вот многообразие для параметризованной конструкции:
public T Factory<T>(params object[] args): where T is MyBaseClass
{
var argList = new List<object>(args);
var type = typeof(T);
var argtypes = argList.Select(o => o.GetType()).ToArray();
var constructor = type.GetConstructor(argtypes);
return constructor.Invoke(args) as T;
}
И, конечно же; Как и в первом примере, это вызовет исключение nullpointer, если оно не может найти соответствующий конструктор...
Ответ 2
class Potato
{
}
class Potato1 : Potato
{
public Potato1(object[] param) { }
}
class Potato2 : Potato
{
public Potato2(object[] param);
}
enum MyEnum
{
E1, E2
}
Dictionary<MyEnum, Func<object[], Potato>> dict = new Dictionary<MyEnum, Func<object[], Potato>>(){
{MyEnum.E1,(d)=>new Potato1(d)},
{MyEnum.E2,(d)=>new Potato2(d)}
};
Potato Factory(MyEnum e, object[] param)
{
return dict[e](param);
}
Ответ 3
Если я правильно понял, вы хотите иметь ссылку на статический класс. Это невозможно в С#.
только один пример реализации метода factory:
http://www.codeproject.com/Tips/328826/implementing-Factory-Method-in-Csharp
Ответ 4
Язык С# не поддерживает мета классы.
Таким образом, вам придется реализовать свой factory по-другому. Один из способов - использовать оператор switch для перечисления:
switch (aEnum)
{
case myEnum1:
return new MyClass1();
case myEnum2:
return new MyClass2();
.....
}
Другим широко используемым вариантом является сделать это с помощью отражения, которое позволит вам писать код ближе к тому, что вы привыкли делать.
И еще один вариант - заменить словарь словаря на словарь делегатов, которые возвращают новый экземпляр вашего объекта. С синтаксисом лямбда этот параметр дает очень чистый код.
Недостатком рефлексии является то, что вы отказываетесь от безопасности типа времени компиляции. Поэтому, в то время как подход, основанный на отражении, вероятно, ближе всего к коду Delphi в вопросе, это не тот маршрут, который я лично выбрал бы.
Вместо того, чтобы пытаться обучить ваше решение Delphi на язык, который не хочет этого подхода, я предлагаю вам найти самое идиоматическое решение С#. Начните с веб-поиска для класса factory.