Класс 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);
    }

Ответ 4

Язык С# не поддерживает мета классы.

Таким образом, вам придется реализовать свой factory по-другому. Один из способов - использовать оператор switch для перечисления:

switch (aEnum)
{
     case myEnum1:
         return new MyClass1();
     case myEnum2:
         return new MyClass2();
     .....
}

Другим широко используемым вариантом является сделать это с помощью отражения, которое позволит вам писать код ближе к тому, что вы привыкли делать.

И еще один вариант - заменить словарь словаря на словарь делегатов, которые возвращают новый экземпляр вашего объекта. С синтаксисом лямбда этот параметр дает очень чистый код.

Недостатком рефлексии является то, что вы отказываетесь от безопасности типа времени компиляции. Поэтому, в то время как подход, основанный на отражении, вероятно, ближе всего к коду Delphi в вопросе, это не тот маршрут, который я лично выбрал бы.

Вместо того, чтобы пытаться обучить ваше решение Delphi на язык, который не хочет этого подхода, я предлагаю вам найти самое идиоматическое решение С#. Начните с веб-поиска для класса factory.