2016-03-21 2 views
1

Есть много примеров, в которых вы можете получить Enum от пользовательского атрибута, как здесь Get Enum from Description attributeПолучить Enum на пользовательский атрибут (Generic)

public static class EnumEx 
{ 
    public static T GetValueFromDescription<T>(string description) 
    { 
     var type = typeof(T); 
     if(!type.IsEnum) throw new InvalidOperationException(); 
     foreach(var field in type.GetFields()) 
     { 
      var attribute = Attribute.GetCustomAttribute(field, 
       typeof(DescriptionAttribute)) as DescriptionAttribute; 
      if(attribute != null) 
      { 
       if(attribute.Description == description) 
        return (T)field.GetValue(null); 
      } 
      else 
      { 
       if(field.Name == description) 
        return (T)field.GetValue(null); 
      } 
     } 
     throw new ArgumentException("Not found.", "description"); 
     // or return default(T); 
    } 
} 

Но здесь проблема в том, что вы должны жестко закодировать AttributeType т.е. typeof(DescriptionAttribute)) as DescriptionAttribute

Как преобразовать этот пример в Generic extension так, чтобы мне не пришлось жестко закодировать CustomAttributeType.

+1

Как идея, вы можете добавить еще один общий параметр для метода, но вы должны знать значение и использование входного параметра для возможности поиска с его помощью. Например, теперь вы можете получить этот критерий 'if (attribute.Description == description)', но как насчет того, когда вы передали общий параметр? –

+2

Как бы вы перевели это тогда: 'attribute.Description', если' attribute' не является 'DescriptionAttribute'? – HimBromBeere

ответ

5

Это будет работать для любого атрибута, где вы хотите, чтобы сравнить значения как строки:

public static TEnum GetValueFromAttribute<TEnum, TAttribute> 
      (string text, Func<TAttribute, string> valueFunc) where TAttribute : Attribute 
{ 
    var type = typeof(TEnum); 
    if(!type.IsEnum) throw new InvalidOperationException(); 
    foreach(var field in type.GetFields()) 
    { 
     var attribute = Attribute.GetCustomAttribute(field, typeof(TAttribute)) as TAttribute; 
     if(attribute != null) 
     { 
      if(valueFunc.Invoke(attribute) == text) 
       return (TEnum)field.GetValue(null); 
     } 
     else 
     { 
      if(field.Name == text) 
       return (TEnum)field.GetValue(null); 
     } 
    } 
    throw new ArgumentException("Not found.", "text"); 
    // or return default(T); 
} 

Что вы бы тогда называть так:

var value = GetValueFromAttribute<MyEnum, Description>("desc_text", a => a.Description); 
+0

Вы можете даже напрямую вызвать свою функцию без использования 'Invoke' для обеспечения безопасности типа:' if (valueFunc (attribute) == text) '. Однако действительно классный ответ. – HimBromBeere

+0

@HimBromBeere Это то же самое (просто ярлык 'Invoke') –

0

Вы можете добавить интерфейс IDescription, что ваши характеристики:

public interface IDescription 
{ 
    string Description { get; } 
} 

public static class EnumEx 
{ 
    public static T GetValueFromDescription<T, TAttribute>(string description) where TAttribute : Attribute, IDescription 
    { 
     var type = typeof(T); 

     if (!type.IsEnum) throw new InvalidOperationException(); 

     foreach (var field in type.GetFields(BindingFlags.Public | BindingFlags.Static)) 
     { 
      var attribute = (IDescription)Attribute.GetCustomAttribute(field, typeof(TAttribute)); 

      if (attribute != null) 
      { 
       if (attribute.Description == description) 
       { 
        return (T)field.GetValue(null); 
       } 
      } 
      else 
      { 
       if (field.Name == description) 
       { 
        return (T)field.GetValue(null); 
       } 
      } 
     } 

     throw new ArgumentException("Not found.", "description"); 
     // or return default(T); 
    } 
} 

или эквивалент с полным основанием Класс:

public abstract class BaseDescriptionAttribute : Attribute 
{ 
    public string Description { get; protected set; } 
} 

public static class EnumEx 
{ 
    public static T GetValueFromDescription<T, TAttribute>(string description) where TAttribute : BaseDescriptionAttribute 
    { 
     var type = typeof(T); 

     if (!type.IsEnum) throw new InvalidOperationException(); 

     foreach (var field in type.GetFields(BindingFlags.Public | BindingFlags.Static)) 
     { 
      var attribute = (BaseDescriptionAttribute)Attribute.GetCustomAttribute(field, typeof(TAttribute)); 
0

добавить новый обобщенный тип

public static T GetValueFromDescription<T, K>(string description) 

и использовать его в GetCustomerAttribute

var attribute = Attribute.GetCustomAttribute(field, typeof(K)); 
Смежные вопросы