2009-10-24 25 views
35

Czy jest możliwe w języku C#, aby utworzyć System.Collections.Generic.Dictionary<TKey, TValue> gdzie TKey jest bezwarunkowe klasa i TValue - anonimowy klasy z wielu właściwości, na przykład - nazwa kolumny bazy danych i jest zlokalizowana nazwa.Słownik gdzie wartość jest anonimowy typ C#

coś takiego:

new { ID = 1, Name = new { Column = "Dollar", Localized = "Доллар" } } 
+0

Bardzo podobny (z LINQ): [A generic lista anonimowej klasy] (http://stackoverflow.com/questions/612689/a-generic-list- of-anonymous-class) – nawfal

+0

. Wybierz (...). AsEnumerable(). ToDictionary (k => k.id, v => v jako obiekt) pracował dla mnie. Moja zmienna to Słownik Ravi

+0

@Ravishankar: Najprawdopodobniej nie potrzebujesz tutaj 'AsEnumerable()'. Nie dodaje niczego na wierzchu 'Wybierz()'. – abatishchev

Odpowiedz

38

Nie można zadeklarować taki rodzaj słownika bezpośrednio (są kludges ale są to wyłącznie w celach rozrywkowych i nowość), ale jeśli dane pochodzące z IEnumerable lub IQueryable źródło, można dostać jeden za pomocą operatora LINQ ToDictionary i wystające wymagany klucz i wartość (anonimowo) od wpisanego elementów kolejności:

var intToAnon = sourceSequence.ToDictionary(
    e => e.Id, 
    e => new { e.Column, e.Localized }); 
16

Jak itowlsonsaid, nie można zadeklarować taką bestię, ale można rzeczywiście tworzyć jedno:

static IDictionary<TKey, TValue> NewDictionary<TKey, TValue>(TKey key, TValue value) 
{ 
    return new Dictionary<TKey, TValue>(); 
} 

static void Main(string[] args) 
{ 
    var dict = NewDictionary(new {ID = 1}, new { Column = "Dollar", Localized = "Доллар" }); 
} 

Nie jest jasne, dlaczego chcesz faktycznie chcą użyć kodu tak.

+10

Dlaczego? Mogę wymyślić kilka powodów. Tu jest jeden. Rozważmy na przykład słownik służący do zapamiętania funkcji n-ary, powiedzmy funkcję czterech argumentów int. W następnej wersji CLR oczywiście wystarczy użyć 4-tki, ale w C# 3 można utworzyć słownik anonimowego typu {int, int, int, int}, gotowe, bez potrzeby definiowania własnego typ krotki. –

+9

Mam teraz kolejny wpis w sekcji "szczotki ze sławą" na mojej stronie głównej! :-) –

3

Można zrobić refection

public static class ObjectExtensions 
{ 
    /// <summary> 
    /// Turn anonymous object to dictionary 
    /// </summary> 
    /// <param name="data"></param> 
    /// <returns></returns> 
    public static IDictionary<string, object> ToDictionary(this object data) 
    { 
     var attr = BindingFlags.Public | BindingFlags.Instance; 
     var dict = new Dictionary<string, object>(); 
     foreach (var property in data.GetType().GetProperties(attr)) 
     { 
      if (property.CanRead) 
      { 
       dict.Add(property.Name, property.GetValue(data, null)); 
      } 
     } 
     return dict; 
    } 
} 
+0

Dobry pomysł. Możesz również ustawić go jako ogólny: 'public static IDictionary ToDictionary (dane tego obiektu) {}' – abatishchev

3

myślę ASP.NET MVC nie wyjście w czasie kwestia ta została dokonana. Umożliwia konwersję anonimowych obiektów do słowników wewnętrznie.

Wystarczy spojrzeć na przykład na HtmlHelper class. Metoda tłumacząca obiekty na słowniki to AnonymousObjectToHtmlAttributes. Jest to specyficzne dla MVC i zwraca wartość RouteValueDictionary.

Jeśli chcesz coś bardziej ogólny, spróbuj tego:

public static IDictionary<string,object> AnonymousObjectToDictionary(object obj) 
{ 
    return TypeDescriptor.GetProperties(obj) 
     .OfType<PropertyDescriptor>() 
     .ToDictionary(
      prop => prop.Name, 
      prop => prop.GetValue(obj) 
     ); 
} 

Jeden zachwycaliśmy advatages tej realizacji jest to, że zwraca pusty słownika dla null obiektów.

A oto jedna wersja ogólna:

public static IDictionary<string,T> AnonymousObjectToDictionary<T>(
    object obj, Func<object,T> valueSelect 
) 
{ 
    return TypeDescriptor.GetProperties(obj) 
     .OfType<PropertyDescriptor>() 
     .ToDictionary<PropertyDescriptor,string,T>(
      prop => prop.Name, 
      prop => valueSelect(prop.GetValue(obj)) 
     ); 
} 
+0

Dzięki za powiadomienie! Wadą takiej metody, którą mogę nazwać, jest użycie refleksji. – abatishchev

+0

@abatishchev Myślę, że niemożliwe jest rozwiązanie problemu bez refleksji. Nie jestem pewien, ale czytanie właściwości z TypeDescriptor może być bardziej efektywne niż w zwykłym .GetType(). GetProperties(). BTW, użyłem ILSpy na HtmlHelper i robi to prawie dokładnie to samo. – jpbochi