2009-08-02 5 views
3

Ich versuche, eine benutzerdefinierte Methode zu schreiben, eine Listview-Steuerelement zu füllen Generics mit:Wie schreibe ich eine Methode, die Daten aus jeder Klasse mit Generics ausgeben kann?

private void BindDataToListView(List<T> containerItems) 
    { 
     this.View = View.Details; 
     this.GridLines = true; 
     this.FullRowSelect = true; 

     if (this.Items.Count > 0) 
      this.Items.Clear(); 

     this.BeginUpdate(); 

     int i = 0; 
     foreach (T item in containerItems) 
     { 
      // do something 
     } 

     this.EndUpdate(); 
    } 

Die Parameter containerItems können viele Einzelteile haben, da ich die Verwendung von Generika bin. Aber ich bleibe in der foreach Schleife stecken. Wie greife ich auf die Werte in containerItems zu?

Muss ich Reflexion für jede Instanz von T in der foreach-Schleife verwenden? Ich denke, ich tue, um den Namen der Eigenschaft abzurufen. Aber sobald ich den Eigenschaftsnamen des Typs T habe, wie kann ich den Wert abrufen?

Antwort

2

der häufigste Weg, dies zu tun (mit WinForms) ist über TypeDescriptor; Dies ermöglicht es Ihnen, Dinge DataTable die gleiche wie Klassen zu verwenden; das „voll“ Muster ist recht komplex (und beinhaltet für IListSource Überprüfung, ITypedList, etc, aber die kurze Version ist, die zur Verfügung stehenden Eigenschaften zu erhalten:

PropertyDescriptorCollection props = TypeDescriptor.GetProperties(typeof(T)); 

eine benannte Eigenschaft zu erhalten:

PropertDescriptor prop = props[propName]; 

Um einen Wert für eine Instanz (sourceObject) zu erhalten:

object val = prop.GetValue(sourceObject); 

Um einen Wert als String zu machen (die bezeichnete Konverter):

string s = prop.Converter.ConvertToString(val); 
+0

ist dies das gleiche wie obj.GetType(). GetProperty ("Nachname"). GetValue (obj, null)? –

+0

Nicht ganz; Wichtig ist, dass benutzerdefinierte Modelle (via (TypeDescriptionProvider) berücksichtigt werden. Um ** volle ** Unterstützung zu erhalten (für benutzerdefinierte 'ITypedList' usw.) benötigen Sie zusätzliche Arbeit, aber es bedeutet, dass Sie * dies * unterstützen müssen , Sie müssen nicht alles neu schreiben.Sie unterstützt auch Dinge wie HyperDescriptor ohne Änderungen; -p –

2

Sie könnten T auf eine Schnittstelle beschränken und diese Schnittstelle in der Iteration verwenden.

0

Wenn die Elemente in der Liste vollständig unbeschränkt sind, können Sie sie einfach als Typ object behandeln. Sie rufen GetType() auf, um den Typ des Objekts abzurufen. Auf diesem können Sie GetProperties() aufrufen, um ein Array von PropertyInfo Objekten zu erhalten. Und auf denen können Sie GetValue() aufrufen, um den Wert der Eigenschaft abzurufen.

Wenn Sie bereits den Namen einer Eigenschaft wissen, rufen Sie einfach GetProperty() es abzurufen:

string valueAsString = item.GetType().GetProperty("Something") 
         .GetValue(item, null).ToString(); 
0

ich nicht ganz verstehen, was Sie fragen, aber ich denke, dass diese Sie in der Punkt richtige Richtung. Bitte erkundigen Sie sich, ob es helfen kann und es unklar ist.

Sie können eine bestimmte Eigenschaft eines Objekts zugreifen mithilfe von Reflektion über

object o; 
PropertyInfo info = o.GetType().GetProperty().GetProperty("NameOfPropertyIWant"); 

und Sie können den Wert über

object value = info.GetValue(o, null); 

Jetzt erhalten, wenn Sie eine Eigenschaft sein werden Zugriff auf den gleichen Namen für Objekte verschiedener Typen, sollten Sie eine Schnittstelle hinzufügen

public interface IHasThePropertyIWant { 
    object NameOfPropertyIWant { get; } 
} 

Dann können Sie diese erzwingen über

void BindDataToListView(List<T> containerItems) where T : IHasThePropertyIWant 

und im aussehen verwenden, so

foreach (T item in containerItems) { 
    object o = item.NameOfPropertyIWant; 
    // do something with o 
} 
1

Was bedeutet T darstellen?
Wie es jetzt ist, ist es eine generische Art und es kann ... alles sein.

Also, was ich tun würde, ist eine Schnittstelle IListViewBindable oder so etwas zu erstellen. Diese Schnittstelle könnte dann beispielsweise eine Methode 'CreateListViewItem' haben.

Dann würde ich die Methode ändern, so dass eine Beschränkung auf Ihren Typ-Parameter T angelegt wird sagen, dass T IListViewBindable umsetzen müssen, wie folgt aus:

public void BindDataToListView<T>(List<T> containerItems) where T : IListViewBindable 
{} 

In Ihrem BindDataToListView Methode, könnten Sie dann Dazu:

foreach(T item in containerItems) 
{ 
    this.Items.Add (item.CreateListViewItem()); 
} 
0

ObjectListView verwendet Reflektion, genau das zu tun, was Sie zu tun versuchen: ein Listview mit Reflexion zu füllen. Sie könnten sich eine Menge Ärger ersparen, wenn Sie es benutzen. Es hat bereits alle schwierigen Probleme gelöst, denen Sie auf diesem Weg begegnen werden.

Wenn Sie wirklich, wirklich, es selbst tun wollen, ist die Antwort von Marc (natürlich) völlig richtig.

Verwandte Themen