2013-08-08 8 views
9

Przepraszam za ilość kodu, ale łatwiej jest to wyjaśnić w ten sposób.Generics, enums i niestandardowe atrybuty - czy to możliwe?

mam zwyczaju przypisywać CustomUserData realizowane w następujący sposób:

public class CustomUserData : Attribute 
{ 
    public CustomUserData(object aUserData) 
    { 
     UserData = aUserData; 
    } 
    public object UserData { get; set; } 
} 

i metodę rozszerzenia dla teksty stałe jak:

public static class EnumExtensions 
{ 
    public static TAttribute GetAttribute<TAttribute>(this Enum aValue) where TAttribute : Attribute 
    { 
     Type type = aValue.GetType(); 
     string name = Enum.GetName(type, aValue); 
     return type.GetField(name) 
        .GetCustomAttributes(false) 
        .OfType<TAttribute>() 
        .SingleOrDefault(); 
    } 

    public static object GetCustomUserData(this Enum aValue) 
    { 
     CustomUserData userValue = GetAttribute<CustomUserData>(aValue); 
     return userValue != null ? userValue.UserData : null; 
    } 
} 

Mam następnie klasy pomocnika że serializes/deserializes enum, który ma niestandardowe dane powiązane z nią w następujący sposób:

public static class ParameterDisplayModeEnumListHelper 
{ 
    public static List<ParameterDisplayModeEnum> FromDatabase(string aDisplayModeString) 
    { 
     //Default behaviour 
     List<ParameterDisplayModeEnum> result = new List<ParameterDisplayModeEnum>(); 

     //Split the string list into a list of strings 
     List<string> listOfDisplayModes = new List<string>(aDisplayModeString.Split(',')); 

     //Iterate the enum looking for matches in the list 
     foreach (ParameterDisplayModeEnum displayModeEnum in Enum.GetValues(typeof (ParameterDisplayModeEnum))) 
     { 
      if (listOfDisplayModes.FindIndex(item => item == (string)displayModeEnum.GetCustomUserData()) >= 0) 
      { 
       result.Add(displayModeEnum); 
      } 
     } 

     return result; 
    } 

    public static string ToDatabase(List<ParameterDisplayModeEnum> aDisplayModeList) 
    { 
     string result = string.Empty; 

     foreach (ParameterDisplayModeEnum listItem in aDisplayModeList) 
     { 
      if (result != string.Empty) 
       result += ","; 
      result += listItem.GetCustomUserData(); 
     } 

     return result; 
    } 
} 

jednak s jest specyficzny do ParameterDisplayModeEnum i mam kilka teksty stałe, że muszę się leczyć w ten sposób do serializacji/deserializacji tak wolałbym mieć rodzajowe takie jak:

public static class EnumListHelper<TEnum> 
{ 
    public static List<TEnum> FromDatabase(string aDisplayModeString) 
    { 
     //Default behaviour 
     List<TEnum> result = new List<TEnum>(); 

     //Split the string list into a list of strings 
     List<string> listOfDisplayModes = new List<string>(aDisplayModeString.Split(',')); 

     //Iterate the enum looking for matches in the list 
     foreach (TEnum displayModeEnum in Enum.GetValues(typeof (TEnum))) 
     { 
      if (listOfDisplayModes.FindIndex(item => item == (string)displayModeEnum.GetCustomUserData()) >= 0) 
      { 
       result.Add(displayModeEnum); 
      } 
     } 

     return result; 
    } 

    public static string ToDatabase(List<TEnum> aDisplayModeList) 
    { 
     string result = string.Empty; 

     foreach (TEnum listItem in aDisplayModeList) 
     { 
      if (result != string.Empty) 
       result += ","; 
      result += listItem.GetCustomUserData(); 
     } 

     return result; 
    } 
} 

Jednak to nie zadziała jak GetCustomUserData() nie można wywołać. Jakieś sugestie? Nie mogę zmienić użycia niestandardowego atrybutu ani użycia wyrażeń. Szukam ogólnego sposobu na serializację/deserializację bez konieczności pisania konkretnej klasy pomocnika listy za każdym razem.

Wszystkie sugestie zostały docenione.

Odpowiedz

2

Try ten kod:

public static class EnumListHelper 
{ 
    private static void EnsureIsEnum<TEnum>() 
    { 
     if (!typeof(TEnum).IsEnum) 
      throw new InvalidOperationException(string.Format("The {0} type is not an enum.", typeof(TEnum))); 
    } 

    public static List<TEnum> FromDatabase<TEnum>(string aDisplayModeString) 
     where TEnum : struct 
    { 
     EnsureIsEnum<TEnum>(); 
     //Default behaviour 
     List<TEnum> result = new List<TEnum>(); 

     //Split the string list into a list of strings 
     List<string> listOfDisplayModes = new List<string>(aDisplayModeString.Split(',')); 

     //Iterate the enum looking for matches in the list 
     foreach (Enum displayModeEnum in Enum.GetValues(typeof(TEnum))) 
     { 
      if (listOfDisplayModes.FindIndex(item => item == (string)displayModeEnum.GetCustomUserData()) >= 0) 
      { 
       result.Add((TEnum)(object)displayModeEnum); 
      } 
     } 

     return result; 
    } 

    public static string ToDatabase<TEnum>(List<TEnum> aDisplayModeList) 
     where TEnum : struct 
    { 
     EnsureIsEnum<TEnum>(); 
     string result = string.Empty; 

     foreach (var listItem in aDisplayModeList.OfType<Enum>()) 
     { 
      if (result != string.Empty) 
       result += ","; 
      result += listItem.GetCustomUserData(); 
     } 

     return result; 
    } 
} 

var fromDatabase = EnumListHelper.FromDatabase<TestEnum>("test"); 
EnumListHelper.ToDatabase(fromDatabase); 

UPDATE 0

Żeby było jasne, bo nie możemy się ograniczać do rodzajowych Enum powinniśmy sprawdzić, czy typ TEnum jest wylicznikiem i generuje wyjątek, jeśli tak nie jest. Kiedy używamy metody FromDatabase wiemy, że TEnum jest enum, a my możemy napisać ten kod, aby rzucić enum do określonego TEnum:

result.Add((TEnum)(object)displayModeEnum) 

w metodzie ToDatabase wiemy również, że TEnum jest enum i możemy napisać ten kod, aby przekonwertować TEnum do rodzaju Enum:

aDisplayModeList.OfType<Enum>() 
+0

to jest wielki i po prostu starałem się osiągnąć. Dzięki. – TheEdge

+0

Proszę nie tylko zrzucić kod, wyjaśnić, co zrobiłeś. – CodeCaster

+1

@CodeCaster Zaktualizowałem odpowiedź. –

2

Idealnie chcesz ograniczyć TEnum do Enum ale to nie będzie działać, ponieważ nie można ograniczać do rodzajowych Enum Microsoft
Ale spróbuj następujących, może to załatwi ...

if (listOfDisplayModes.FindIndex(item => 
    item == (string)(displayModeEnum as Enum).GetCustomUserData()) >= 0)