Может ли enum вернуть новый экземпляр в C #? - PullRequest
2 голосов
/ 18 мая 2011

Приветствую всех!

Я постараюсь сделать мою проблему проще: у меня есть enum, чтобы выбрать, какой ObjType мне следует использовать (ObjTypeA и ObjTypeB оба наследуются от ObjType). Поэтому я создал метод для расширения заданного enum, чтобы вернуть новый экземпляр в соответствии с выбранным свойством в enum, как показано в коде. Я думаю, что это работает более или менее как шаблон дизайна фабрики. Пока все хорошо, но в итоге, как и в классе MyClass, я могу попытаться создать n экземпляров ObjTypeA или ObjTypeB, но мне придется сталкиваться с оператором if каждый раз, когда я вызываю GetObjTypeInstance() метод. Итак:

  • Может ли enum вернуть экземпляр, например: public enum EObjType { ObjTypeA = new ObjTypeA(), ObjTypeB = new ObjTypeB() }? На самом деле, было бы лучше добавить какой-нибудь метод GetInstance() к ObjTypeA и к опциям ObjTypeB в enum. Если есть способ сделать это, как я могу это сделать? Делая это, я бы избегал этих операторов if на шаге.
  • Есть ли другой (и лучший) способ для этого (если вы поняли мою проблему ...)? Как?

Заранее спасибо!

Следуйте примеру кода:

public static class EObjTypeExt
{
    public static ObjType GetObjTypeInstance(this EObjType ot)
    {
        if (ot == EObjType.ObjTypeA)
        {
            return new ObjTypeA();
        }
        else if (ot == EObjType.ObjTypeB)
        {
            return new ObjTypeB();
        }
        throw new ArgumentOutOfRangeException("unrecognized type!");
    }
}

public enum EObjType { ObjTypeA, ObjTypeB }

public class MyClass
{
    ObjType[] obj { get; set; }

    public MyClass(EObjType otEnum, int n)
    {
        this.obj = new ObjType[n];
        int i = 0;
        while (i < n)
        {
            this.obj[i] = otEnum.GetObjTypeInstance();
            i++;
        }
    }
}

Ответы [ 7 ]

3 голосов
/ 18 мая 2011

Тебе придется где-то байт это яблоко.

Возможно, замените цепочку if/elseif на выражение switch, они прекрасно работают с перечислениями.

2 голосов
/ 18 мая 2011

Вместо использования enum я бы использовал класс, который выглядит как перечисление:

public class EObjType {
    public static readonly EObjType ObjTypeA = new EObjType(() => (ObjType)(new ObjTypeA));
    public static readonly EObjType ObjTypeB = new EObjType(() => (ObjType)(new ObjTypeB));

    private readonly Func<ObjType> generator;
    private EObjType(Func<ObjType> generator) {
        this.generator = generator;
    }

    public ObjType GetInstanceOfObjType() {
        return generator();
    }
}

Затем вы можете использовать его точно так же, как вы были перечислением.

EObjType otEnum = EObjType.ObjTypeA;
ObjType obj = otEnum.GetInstanceOfObjType();
1 голос
/ 18 мая 2011

Вы можете использовать Activator.CreateInstance.

public class ObjType {}
public class ObjTypeA : ObjType {}
public class ObjTypeB : ObjType {}
public enum EObjType { ObjTypeA, ObjTypeB }

public static class EObjTypeExt
{
    public static ObjType GetObjTypeInstance( EObjType ot)
    {
        object o = Activator.CreateInstance(null,ot.ToString());
        return (ObjType)o;
    }
}
1 голос
/ 18 мая 2011

Вы можете создать фабрику, которая позволяет регистрировать функции, которые соответствуют вашему перечислению, вы можете использовать какой-то процесс регистрации для регистрации ваших различных перечислений

public class ObjectFactory
{
    private readonly Dictionary<MyObjectType, Func<MyObject>> _store = new Dictionary<MyObjectType, Func<MyObject>>();

    public void Register<T>(MyObjectType type) where T: MyObject, new()
    {            
        this.Register(type, () => new T());
    }

    public void Register(MyObjectType type, Func<MyObject> factory)
    {
        _store.Add(type, factory);
    }

    public MyObject CreateInstance(MyObjectType type)
    {
        Func<MyObject> factory;
        if(_store.TryGetValue(type, out factory))
        {
            return factory.Invoke();
        }
        return null;
    }
}

public enum MyObjectType { A, B }

public class MyObject {}

public class MyObjectA : MyObject {}
public class MyObjectB : MyObject {}

Использование следующим образом

var factory = new ObjectFactory();
factory.Register<MyObjectA>(MyObjectType.A);
factory.Register<MyObjectB>(MyObjectType.B);

var a = factory.CreateInstance(MyObjectType.A);
var b = factory.CreateInstance(MyObjectType.B);

Assert.IsInstanceOf(typeof(MyObjectA), a);
Assert.IsInstanceOf(typeof(MyObjectB), b);
1 голос
/ 18 мая 2011

Как указывает Дэнни Варод, словарь, сопоставляющий значения перечисления с их типами (или с функциями, создающими эти типы), позволит вам избежать операторов if. Поскольку enum на самом деле представляет собой целое число снизу, массив будет более эффективным в использовании памяти и времени, но читабельность здесь, вероятно, наиболее важна.

1 голос
/ 18 мая 2011

Я не уверен, что на самом деле выступил бы за такой подход, но вы можете вызвать метод enSt ToString (), рассматривать его как имя вашего класса и использовать отражение для создания экземпляра объекта этого типа.

Одним из преимуществ этого является то, что вы можете отразить и получить тип один раз, а затем вызвать конструктор n раз в цикле.

1 голос
/ 18 мая 2011

Вам необходимо использовать фабричный или другой шаблон проектирования.

Например, вы можете удерживать словарь от ключа перечисления до значения типа, чтобы получить желаемый тип класса, используя выбранное значение перечисления. Затем с помощью отражения создайте новый экземпляр (объект) полученного типа.

Инициализировать значения статического словаря, используя статический конструктор класса фабрики. Вы можете ввести значения вручную или, что еще лучше, загрузить возможные значения из файла конфигурации.

...