2009-09-11 20 views
42

Miałem następujący problem dzisiaj i zastanawiałem się, czy istnieje rozwiązanie mojego problemu.Obsada do anonimowego typu

Moim pomysłem było stworzenie anonimowych klas i używać go jako źródło danych dla WinForm BindingSource:

public void Init() 
{ 
    var option1 = new 
        { 
         Id = TemplateAction.Update, 
         Option = "Update the Templates", 
         Description = "Bla bla 1." 
        }; 

    var option2 = new 
        { 
         Id = TemplateAction.Download, 
         Option = "Download the Templates", 
         Description = "Bla bla 2." 
        }; 

    var list = new[] {option1, option2}.ToList(); 

    bsOptions.DataSource = list; // my BindingSource 

    // cboTemplates is a ComboBox 
    cboTemplates.DataSource = bsOptions; 
    cboTemplates.ValueMember = "Id"; 
    cboTemplates.DisplayMember = "Option"; 

    lblInfoTemplates.DataBindings.Add("Text", bsOptions, "Description"); 
} 

który działa dobrze do tej pory.

Problem miałem jest, aby uzyskać identyfikator z „Current” własność BindingSource, bo nie może oddać go z powrotem do Anonymous Typ:

private void cmdOK_Click(object sender, EventArgs e) 
{ 
    var option = (???)bsOptions.Current; 
} 

Chyba nie ma sposobu, aby dowiedzieć się typu "Bieżąca" i uzyskać dostęp do właściwości "Id"? Może ktoś ma dobre rozwiązanie ...

Wiem, że istnieją inne (a także lepsze) sposoby na uzyskanie Id (odbicie, odczytanie wartości z ComboBox, nie używanie anonimowych tpyes, ...) m tylko courious, jeśli można uzyskać typ z bsOptions.Current w elegancki sposób.

+0

Br ... anonimowy klasy mogą być przydatne (czasami), ale tak naprawdę, używane w ten sposób, dla mnie jest to regresja do VB wieku: /. –

+1

Poczekaj, aż dynamiczne wejdzie na scenę, ciesz się, że widzimy tylko pytania o przekazywanie anonimowych obiektów. –

+1

Dobra, przy odrobinie szczęścia będziemy mieli zupełnie nowy atrybut "markizy" na etykiecie: D –

Odpowiedz

69

Uwaga, zgodnie z komentarzem, Chciałbym tylko podkreślić, że ja też zalecamy użycie prawdziwy typ, gdy trzeba przekazać ją wokół programu takiego. Typy anonimowe powinny być używane tylko lokalnie w jednej metodzie na raz (moim zdaniem), ale tak czy inaczej, oto reszta mojej odpowiedzi.


Można to zrobić za pomocą sztuczki, za oszukiwanie kompilator do wnioskowania odpowiedni rodzaj dla Ciebie:

using System; 

namespace ConsoleApplication4 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      var a = new { Id = 1, Name = "Bob" }; 
      TestMethod(a); 

      Console.Out.WriteLine("Press enter to exit..."); 
      Console.In.ReadLine(); 
     } 

     private static void TestMethod(Object x) 
     { 
      // This is a dummy value, just to get 'a' to be of the right type 
      var a = new { Id = 0, Name = "" }; 
      a = Cast(a, x); 
      Console.Out.WriteLine(a.Id + ": " + a.Name); 
     } 

     private static T Cast<T>(T typeHolder, Object x) 
     { 
      // typeHolder above is just for compiler magic 
      // to infer the type to cast x to 
      return (T)x; 
     } 
    } 
} 

Sztuką jest, że wewnątrz zespołu, ten sam typ anonimowy (te same właściwości, tej samej kolejności) rozwiązuje ten sam typ, co sprawia, że ​​powyższy trik działa.

private static T CastTo<T>(this Object value, T targetType) 
{ 
    // targetType above is just for compiler magic 
    // to infer the type to cast x to 
    return (T)x; 
} 

Wykorzystanie:

var value = x.CastTo(a); 

Ale my naprawdę przesuwanie granic tutaj. Użyj prawdziwego typu, będzie wyglądać i czuć się czystszy.

+0

Nie mam jak to jednak, ponieważ może być podatne na błędy, o wiele lepiej po prostu stworzyć prawdziwą klasę do przechowywania wartości. –

+0

Zgadzam się, chociaż nie jest to tak naprawdę podatne na błędy, ale zgadzam się, że tutaj jest prawdziwy typ, ja zredagowałem odpowiedź, aby wyjaśnić. –

+4

Według Madsa Torgersena, zespół C# określa tę sztuczkę jako "rzut przez przykład". Zobacz jego komentarz (pierwszy) na temat tego artykułu: http://tomasp.net/blog/cannot-return-anonymous-type-from-method.aspx – LukeH

8

Cytując MSDN:

anonimowy typ nie może być oddane do dowolnego interfejsu lub rodzaju, z wyjątkiem obiektu.

6

W języku C# 3.0 jest to niemożliwe. Będziesz musiał poczekać na C# 4.0, który pozwala na dostęp do właściwości w środowisku wykonawczym za pomocą zmiennych "dynamicznych".

0

Można również zadeklarować tablicę anonimowych typów bezpośrednio z tej składni:

var data = new [] { 
    new {Id = 0, Name = "Foo"}, 
    new {Id = 42, Name = "Bar"}, 
}; 
1
public class MyExtensMethods{ 

    public static T GetPropertyValue<T>(this Object obj, string property) 
    { 
     return (T)obj.GetType().GetProperty(property).GetValue(obj, null); 
    } 
} 

class SomeClass 
{ 
    public int ID{get;set;} 
    public int FullName{get;set;} 
} 


// casts obj to type SomeClass 
public SomeClass CastToSomeClass(object obj) 
{ 
    return new SomeClass() 
    { 
     ID = obj.GetPropertyValue<int>("Id"), 
     FullName = obj.GetPropertyValue<string>("LastName") + ", " + obj.GetPropertyValue<string>("FirstName") 
    }; 
} 

... .następnie możesz wykonać:

var a = new { Id = 1, FirstName = "Bob", LastName="Nam" }; 
SomeClass myNewVar = CastToSomeClass(a); 
+1

, ale piękno anonimowych gubią się tutaj ... muszę napisać SomeClasses ... – gsharp

+0

@ gsharp. Moim przypadkiem użycia jest testowanie jednostki Jsonresult, która wysyła anonimowy typ wielu zrealizowanych klas. Więc już mam SomeClasses, ale chciałem anonimowy typ do przekazania json. Działa to idealnie dla mnie dzięki. –

15

Zamiast odlewania do niestandardowego typu spróbuj użyć typu dynamicznego.

Twój obsługi zdarzeń będzie wyglądać mniej więcej tak:

private void cmdOK_Click(object sender, EventArgs e) 
{ 
    dynamic option = bsOptions.Current; 
    if (option.Id == 1) { doSomething(); } 
     else { doSomethingElse(); } 
} 
+2

+1 - Jest to dobra opcja w C# 4.0. opcja.Id zostanie oceniona w czasie wykonywania w tym przypadku. –

Powiązane problemy