it-swarm.com.de

Lambda-Eigenschaftswähler als Parameter

Ich muss eine Methode so ändern, dass sie über einen zusätzlichen Parameter verfügt, der einen Lambda-Ausdruck benötigt, der für ein internes Objekt verwendet wird, um den Wert der angegebenen Eigenschaft zurückzugeben. Verzeihen Sie meine wahrscheinliche falsche Verwendung der Terminologie, da dies mein erster Ausflug in LINQ-Ausdrücke ist!

Ich habe versucht, nach einer Antwort zu suchen, aber wie gesagt, meine Terminologie scheint zu sein und die Beispiele, die ich finden kann, sind viel zu komplex oder sie behandeln Ausdrücke für Auflistungsfunktionen wie .Where(), die mir vertraut sind.

Was ich bisher habe (reduzierte Version):

class MyClass
{
    private MyObject _myObject = new MyObject() { Name = "Test", Code = "T" };

    private string MyMethod(int testParameter, ??? selector)
    {
        //return _myObject.Name;
        //return _myObject.Code;
        return ???;
    }
}

Ich würde es gerne so nennen:

string result = _myClassInstance.MyMethod(1, (x => x.Name));

oder:

string result = _myClassInstance.MyMethod(1, (x => x.Code));

Offensichtlich sind die Teile, die mir fehlen, der Parameter selector in MyMethod, wie er auf die lokale Variable angewendet wird und wie die erforderliche Eigenschaft an die Methode übergeben wird, wenn ich sie aufrufe.

Jede Hilfe wäre willkommen, auch zusätzliche Bonuspunkte für eine VB.NET-Lösung sowie die endgültige Implementierung müssen leider in unserem einsamen VB -Projekt sein!

26
XN16
private string MyMethod(int testParameter, Func<MyObject, string> selector)
{
    return selector(_myObject);
}

Bei Verwendung von Func-Delegaten ist der letzte Parameter der Rückgabetyp und der erste N-1 die Argumenttypen. In diesem Fall gibt es ein einzelnes MyObject-Argument für selector und es gibt eine string zurück.

Sie können es wie folgt aufrufen:

string name = _myClassInstance.MyMethod(1, x => x.Name);
string result = _myClassInstance.MyMethod(1, x => x.Code);

Da der Rückgabetyp von MyMethod dem Rückgabetyp Ihres selector-Delegaten entspricht, können Sie ihn als generisch definieren:

private T MyMethod<T>(int testParameter, Func<MyObject, T> selector)
{
    MyObject obj = //
    return selector(obj);
}

EDIT: Ich kenne VB.Net nicht, aber es sieht so aus:

Public Function MyMethod(testParameter as Integer, selector as Func(Of MyObject, String))
    Return selector(_myObject)
End Function

und die generische Version wäre:

Public Function MyMethod(Of T)(testParameter as Integer, selector Func(Of MyObject, T))
    Return selector(_myObject)
End Function
35
Lee

Bei LINQ geht es nur um das Abfragen von Listen. Die Antworten, die ich gesehen habe, beziehen sich nicht auf Abfragen. Ich zeige Ihnen einen Ansatz, der sehr flexibel ist, da Sie auf diese Weise leicht Ihre eigenen Linq-Funktionen schreiben können, um vorhandene Funktionen zu erweitern oder eigene Funktionen zu schreiben.

In diesem Beispiel verbessere ich die Distinct-Funktion von Linq so, dass Sie ein Feld angeben können, das für die Gruppierung verwendet wird.

Verwendung (Beispiel):

var myQuery=(from x in Customers select x).MyDistinct(d => d.CustomerID);

In diesem Beispiel wird die Abfrage nach CustomerID gruppiert und das erste Element jeder Gruppe wird zurückgegeben.

Deklaration von MyDistinct:

public static class Extensions
{
    public static IEnumerable<T> MyDistinct<T, V>(this IEnumerable<T> query, 
                                                    Func<T, V> f)
    {
        return query.GroupBy(f).Select(x=>x.First());
    }
}

Sie können sehen, dass f, der 2. Parameter, als Func<T, V> deklariert ist, sodass er von der .GroupBy-Anweisung verwendet werden kann.


Zurück zum Code in Ihrer Frage, wenn Sie dies erklärt haben

class MyObject
{
    public string Name;
    public string Code;
}

private MyObject[] _myObject = {
    new MyObject() { Name = "Test1", Code = "T"},
    new MyObject() { Name = "Test2", Code = "Q"},
    new MyObject() { Name = "Test2", Code = "T"},
    new MyObject() { Name = "Test5", Code = "Q"}
};

sie können das mit der neu definierten Funktion MyDistinct wie folgt verwenden:

var myQuery = (from x in _myObject select x).MyDistinct(d => d.Code);

was wird wiederkommen

Name Code
Test1 T
Test2 Q 

oder Sie können .MyDistinct(d => d.Name) in der Abfrage verwenden, die Folgendes zurückgibt:

Name Code
Test1 T
Test2 Q
Test5 Q 

Beachten Sie, dass MyDistinct mit den Generics T und V deklariert wird, die richtigen Objekttypen automatisch erkennt und verwendet und MyObject-Elemente zurückgibt.


Erweiterte Verwendung

Beachten Sie, dass MyDistinct immer das erste Element jeder Gruppe übernimmt. Was ist, wenn Sie eine Bedingung benötigen, die definiert, welches Element Sie benötigen?

So kannst du es machen:

public static class Extensions
{
    public static IEnumerable<T> MyDistinct<T, V>(this IEnumerable<T> query,
                                                    Func<T, V> f, 
                                                    Func<IGrouping<V,T>,T> h=null)
    {
        if (h==null) h=(x => x.First());
        return query.GroupBy(f).Select(h);
    }
}

Mit dieser Änderung können Sie sie entweder genau wie zuvor verwenden, d. H. Indem Sie einen Parameter wie .MyDistinct(d => d.Name) angeben. Sie können jedoch auch eine Bedingung wie x => x.FirstOrDefault(y => y.Name.Contains("1")||y.Name.Contains("2")) als zweiten Parameter wie folgt angeben:

var myQuery2 = (from x in _myObject select x).MyDistinct(d => d.Name,
        x=>x.FirstOrDefault(y=>y.Name.Contains("1")||y.Name.Contains("2"))
        );

Wenn Sie diese Abfrage ausführen, lautet das Ergebnis:

Name Code
Test1 T
Test2 Q
null

da Test5 die Bedingung nicht erfüllt (es enthält nicht 1 oder 2), erhalten Sie null in der 3. Zeile.

Hinweis: Wenn Sie nur die Bedingung sichtbar machen möchten, können Sie sie noch einfacher implementieren, indem Sie sie wie folgt implementieren:

public static IEnumerable<T> MyDistinct2<T, V>(this IEnumerable<T> query,
                                                Func<T, V> f,
                                                Func<T,bool> h=null
                                                )
{
    if (h == null) h = (y => true);
    return query.GroupBy(f).Select(x=>x.FirstOrDefault(h));
}

In diesem Fall würde die Abfrage nur so aussehen:

var myQuery3 = (from x in _myObject select x).MyDistinct2(d => d.Name,
                    y => y.Name.Contains("1") || y.Name.Contains("2")
                    );

sie müssen also nicht x=>x.FirstOrDefault(... condition ...) schreiben.

3
Matt

in C #

Der Parametertyp, nach dem Sie suchen

private string MyMethod(int testParameter, Func<MyClass,string> selector){
    return selector(_myObject);
}

in VB möchten Sie immer noch Func, die Syntax ist etwas anders.

Function MyMethod(ByVal testParameter As Integer, ByVal selector as Func(Of MyClass,string) as string
    return selector(_myObject)
End Function
2
Mr.Mindor
class MyClass
{
    private MyObject _myObject = new MyObject() { Name = "Test", Code = "T" };

    private string MyMethod(int testParameter, Func<MyObject, string> selector)
    {
        return selector(_myObject );
    }
}
0
Reza ArabQaeni

Sie können dies mit einem Delegierten Ihres Wählers tun:

delegate string SampleDelegate(MyObject obj);

private string MyMethod(int testParameter, SampleDelegate selector)
{
    return selector(_myObject);
}
0
Teejay

Sie suchen wahrscheinlich nach der Delegate-Klasse ("Delegate" in VB, "Delegate" in C #) oder einem ihrer Untertypen.

Diese Seite enthält einige Beispiele, die möglicherweise nützlich sind, insbesondere am unteren Rand der Seite.

Hier ist ein VB Beispiel dafür, was Sie tun möchten:

Public Class MyClass

  Private Property _myObject As MyObject = New MyObject With {.Name = "Test", .Code = "T"}

  Private Function MyMethod(testParameter As Integer, selector As Func(Of MyObject, String)) As String
    Return selector(_myObject).ToString
  End Function

End Class
0
Douglas Barbin