2017-05-01 3 views
1
List<T> objectList = GetList(); 

foreach (T setName in setNames) 
{ 
List<T> list = objectList.Where(x => x.QualificationID == setName).ToList(); 
redisClient.SetAdd<string>("Qualification:" + setName, list.Select(x => x.ProductID).ToString()); 
} 

In Zeile 3, hat T keine Definition für ‚QualificationID‘ und keine Erweiterungsmethode enthält ‚QualificationID‘ ein erstes Argument vom Typ T Annahme gefunden werden konnte.Wie eine Liste abzufragen <T> LINQ mit

Ähnlich in Zeile 4, T enthält keine Definition für 'ProductID' und es konnte keine Erweiterungsmethode 'ProductID' gefunden werden, die ein erstes Argument vom Typ T akzeptiert.

Wie können wir die Liste der generischen Objekte mit linq filtern?

EDIT: Es ist nicht möglich, den Eigenschaftswert in einer generischen Methode zu filtern, bis wir den Klassestyp angeben. ähnliches Verfahren erstreckt,

Methode() wobei T: Classtype

wie in den Antworten und Kommentar angegeben.

+2

Verwenden Sie eine generische Art "where T: SomeType" Typ in Ihrer Methode/Klasse-Deklaration. – Abion47

+0

Können Sie mit einem Beispiel sprechen? –

+0

Ich verdächtige 'list.Select (x => x.ProductID) .ToString()' wird nichts nützliches ergeben, da '.Select()' liefert eine 'IEnumerable ', who ist.' ToString() 'Methode gibt den Typ zurück Name. –

Antwort

3

Unter der Annahme, dass Sie einen Basistyp BaseType haben, die die öffentlichen Member QualificiationID und ProductID hat, können Sie Folgendes tun:

void Foo<T>() where T : BaseType 
{ 
    List<T> objectList = GetList(); 

    foreach (T setName in setNames) 
    { 
     List<T> list = objectList.Where(x => x.QualificationID == setName).ToList(); 
     redisClient.SetAdd<string>("Qualification:" + setName, list.Select(x => x.ProductID).ToString()); 
    } 
} 

Dies setzt voraus, dass der generische Typ der Methode spezifisch ist. Wenn es sich um einen generischen Code auf Klassenebene handelt, verschieben Sie einfach die where T : BaseType an die entsprechende Stelle in der Klassendeklaration.


Als Nebenpunkt, der ToString() Teil Ihrer zweiten .Select Anruf wahrscheinlich tun, ist nicht das, was Sie es tut denken. ToString versucht, das Objekt in eine Zeichenfolge zu konvertieren, die standardmäßig den Typnamen zurückgibt. Das bedeutet, dass alles, was Sie daraus machen, etwas in Richtung "System.Linq.IEnumerable+WhereSelectEnumerableIterator`1" ist. Um eine Zeichenfolge aus der LINQ to tatsächlich zu bekommen, werden Sie es in einen String-Konstruktor ernähren müssen und es ein bisschen ändern sich:

redisClient.SetAdd<string>("Qualification:" + setName, String.Join("", list.Select(x => x.ProductID.ToString())); 
+0

spezifizieren. In meinem Fall kann das T von irgendeinem classType sein. –

+2

@KaarthickRaman Offensichtlich kann es nicht, da nicht jede Klasse die 'QualificationID' oder' ProductID' Mitglieder hat. – Abion47

0

Das Problem ist, dass Ihr Compiler nicht weiß, dass Objekte vom Typ T hat Eigenschaften QualificationId und ProductId. Sie müssen es irgendwie dem Compiler mitteilen.

Der allgemeinste Weg, dies zu tun, besteht darin, eine Einschränkung zu T hinzuzufügen, die den Compiler darüber informiert, dass T diese beiden Eigenschaften hat. Dies wird in einem getan where clause

void MyFunc<T>(T obj) where T : ... 

Anstelle der Punkte, können Sie eine Basisklasse setzen, von denen Sie wissen, dass es diese beiden Eigenschaften hat. Allgemeiner ist, dass Sie eine Schnittstelle bereitstellen. Sie versprechen, dass, wann immer Sie MyFunct verwenden, dass das gelieferte obj eines Typs T ist, die die Schnittstelle implementiert:

interface IMyInterface 
{ 
    public int QualificationId {get;} 
    public int ProductId {get;} 
} 

public void MyFunct<T>(List<T> objectList) where T: IMyInterface 
{ 
    // here you know that any T implements IMyInterface, 
    // and thus you can get QualificationId and ProductId 

    List<T> list = objectList 
     .Where(listElement => listElement.QualificationID == setName).ToList(); 
    redisClient.SetAdd<string>("Qualification:" + setName, 
     list.Select(listElement => listElement.ProductID).ToString()); 
} 

Die Schnittstelle Verfahren bevorzugt über dem Basisklassenmethode, denn es gibt Ihnen die Möglichkeit Gebrauch nehmen any T, solange es die Schnittstelle implementiert, auch wenn es eine andere Basisklasse hat

Als Nebenbemerkung: Ich bin mir nicht sicher, was Sie mit SetAdd tun möchten, aber das Ergebnis Ihrer Select ist wahrscheinlich eine Sequenz von ProductIds. Die ToString() dieser Sequenz beschreibt die Sequenz, nicht die Elemente in der Sequenz.Ich bin mir ziemlich sicher, dass das nicht das ist, was Sie wollen

Verwandte Themen