2016-09-10 3 views
0

Как создать экземпляр класса с использованием известных атрибутов? В этом атрибуты являются значениями перечисления.C# как создать экземпляр класса по атрибутам класса

public enum MyEnum 
{ 
    Value1, 
    Value2 
} 

class MyAttribute : Attribute... //attribute definition class 
{ //uses the enum} 

//Main 
abstract class MyMain ... 
{ 
    public static MyMain CreateClass 
    { 
     MyMain newInheritedClass = ? 
    } 
} 

[MyAttribute(MyEnum.Value1)] 
class MyClassA : MyMain ... 

[MyAttribute(MyEnum.Value2)] 
class MyClassB : MyMain ... 
+0

Для этого вы можете использовать [Reflection] (https://msdn.microsoft.com/en-us/library/mt656691.aspx), но чего вы действительно пытаетесь достичь? Вероятно, есть лучший способ сделать это. – InBetween

+0

У меня есть значения перечисления, и вам нужно создать соответствующий класс на основе указанного перечисления. Следовательно: вызов конструктора с MyEnum.Value1 вернет новый экземпляр MyClassA. – KSav

+0

Да, это очевидно из вашего вопроса. Но зачем вам это нужно? Это ваш дизайн? Вы управляете «MyMain» и производными классами или являетесь ли они третьей стороной или кодом, который вы не можете изменить? – InBetween

ответ

0

I согласны с Fabio's answer тем, что использование атрибутов кажется излишним здесь, но у нас недостаточно информации, чтобы действительно знать, почему вы используете этот подход, поэтому я покажу вам, как это будет сделано:

Вашего метод CreateClass должен выглядеть следующим образом:

public static MyMain CreateClass(MyEnum value) 
{ 
    var targetType = Assembly.GetExecutingAssembly() 
          .GetTypes() 
          .Where(t => t.IsSubclassOf(typeof(MyMain)) && 
            t.GetCustomAttribute<MyAttribute>()?.Value == value) 
          .FirstOrDefault(); 

    if (targetType != null) 
     return Activator.CreateInstance(targetType) as MyMain; 

    return null; 
} 

Это presuposes две вещей:

  1. Ваших производные классы, определенные в исполняющей сборке.
  2. Ваши производные классы имеют общедоступные конструкторы без параметров.

Если niether - это случай, вы все равно можете приспособить решение, исследующее немного.

+1

Если 'CreateClass' вызывается часто, я бы рекомендовал только один раз выполнить« GetTypes() »и затем кэшировать соответствующие типы (т. Е. Подклассы родительского класса, которые не являются абстрактными). – flindeberg

+0

@flindeberg Да, это была бы хорошая идея. – InBetween

0

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

public static MyMain CreateInstance(MyEnum attribute) 
{ 
    if(attribute == MyEnum.Value1) 
    { 
     return new MyClassA(); 
    } 
    else 
    { 
     //... 
    } 
} 

Конечно, если у вас есть задача создать экземпляр на основе атрибутов, тогда:

private readonly Dictionary<MyEnum, Type> _Data; 

public Factory(Assembly assembly) 
{ 
    var myAttributeClasses = 
     assembly.GetTypes() 
       .Select(t => new 
       { 
        DirevedType = t, 
        Attribute = (MyAttribute)t.GetCustomAttribute(typeof(MyAttribute)) 
       }) 
       .Where(data => data.Attribute != null); 

    _Data = new Dictionary<MyEnum, Type>(); 
    foreach(var data in myAttributeClasses) 
    { 
     _Data.Add(data.Attribute.EnumValue, data.DerivedType); 
    } 
} 

public MyMain CreateInstance(MyEnum enumvalue) 
{ 
    Type derivedType; 
    if(_Data.TryGetValue(enumvalue, out derivedType) == false) 
     return null; 

    return Activator.CreateInstance(derivedType); 
} 
+0

Я должен был сказать это в первую очередь, но я хочу, чтобы конструктор базового класса очистился от ifs, switch и т. Д. И получил экземпляры класса, используя структуру, свободную от этих операторов. – KSav

+0

@KSav какой конструктор базового класса? Вы используете «ifs and switches» в заводском методе. И что не так с «ifs and switch»? Это программирование ... похоже на то, что я хочу поплавать, но я не хочу промокнуть ... – InBetween

+0

@KSav, во всяком случае, где-то вам нужно поставить 'if или switch' хотя бы один раз. Таким образом, заводский подход хорош на основе информации, которую вы нам дали. Использование атрибутов отличается хорошим подходом для создания возможностей плагина для вашего приложения, например Microsoft имеет [Managed Extensibility Framework (MEF)] (https://msdn.microsoft.com/en-us/library/dd460648 (v = vs.110).aspx), которые используют «программирование атрибутов» – Fabio

Смежные вопросы