Enumerierbar Wählen Sie nach Ausdrucksbaum

c# enumerable expression expression-trees lambda

Frage

Ich studiere "Expression Tree", aber ich kann diese Ausdrücke nicht ausführen:

// first case
someList.Select(p => p.SomeProperty);

und

// second case
someList.Select(p => new OtherClass 
{
    SomeProperty = p.SomeProperty
})

Zu dem "ersten Fall" habe ich folgendes versucht:

var someList = new List<SomeClass>();
someList.Add(new SomeClass { SomeProperty = "Hello" });

var someParam = Expression.Parameter(typeof(SomeClass), "p");
var someProperty = Expression.Property(someParam, "SomeProperty");

Expression.Call(
    typeof(Enumerable),
    "Select",
    new Type[]
    {
        typeof(SomeClass),
        typeof(string)
    },
    Expression.Lambda(
        someProperty,
        someParam
    )
).Dump();

Aber ich bekomme diesen Fehler:

InvalidOperationException: Keine generische Methode 'Select' für den Typ 'System.Linq.Enumerable' ist mit den angegebenen Typargumenten und Argumenten kompatibel. Wenn die Methode nicht generisch ist, sollten keine Typargumente angegeben werden.

Über den "zweiten Fall" habe ich keine Idee, wie es weitergeht.

Kann mich jemand hier führen?

Akzeptierte Antwort

Beruhige dich, nach ein paar Recherchen fand ich, was in meinem Code fehlte ...

Auf den ersten Fall:

Expression.Call(
    typeof(Enumerable),
    "Select",
    new Type[]
    {
        typeof(SomeClass),
        typeof(string)
    },
    Expression.Constant(someList), // <---------------- HERE IT IS
    Expression.Lambda(
        someProperty,
        someParam
    )
);

Im zweiten Fall habe ich den "neuen" Ausdruck über den folgenden Code erstellt:

var bind = Expression.Bind(typeof(OtherClass).GetProperty("SomeProperty"), someProperty);
var otherClassNew = Expression.New(typeof(OtherClass));
var otherClassInit = Expression.MemberInit(otherClassNew, bind);

Wie auch immer, vielen Dank für Ihre Hilfe!


Beliebte Antwort

Einige Beispiele, was Sie tun könnten:

Gegeben

public class SomeClass
{
    public string SomeProperty { get; set; }
}

und

var someList = new List<SomeClass>();
someList.Add(new SomeClass { SomeProperty = "Hello" });

var someParam = Expression.Parameter(typeof(SomeClass), "p");
var someProperty = Expression.Property(someParam, "SomeProperty");

Expression<Func<SomeClass, string>> lambda = Expression.Lambda<Func<SomeClass, string>>(someProperty, someParam); // p => p.SomeProperty

Verwenden eines IEnumerable<SomeClass> ... Beachten Sie die .Compile()

Func<SomeClass, string> compiled = lambda.Compile();
IEnumerable<string> q1 = someList.Select(compiled);

Sie sollten immer nicht verwenden AsQueryable() , aber in Unit - Tests und „Experimente“ Programme (wie diese). Nur um @Peter glücklich zu machen, füge ich eine weitere mögliche Bedingung hinzu: Wenn du wirklich weißt, was es tut ( denke nicht, dass du weißt, was es tut, wirklich !), Dann kannst du es benutzen. Aber wenn Sie es zum ersten Mal benutzen, schlage ich vor, dass Sie nach SO fragen, wenn Sie es richtig benutzen.

IQueryable<SomeClass> queryable = someList.AsQueryable();

Direkte Verwendung der Queryable.Select()

IQueryable<string> q2 = queryable.Select(lambda);

CreateQuery ein Select und verwenden Sie CreateQuery (das ähnelt sehr dem, was intern von Queryable.Select wird), um es in die Abfrage zu "injizieren".

MethodInfo select = (from x in typeof(Queryable).GetMethods()
                    where x.Name == "Select" && x.IsGenericMethod
                    let gens = x.GetGenericArguments()
                    where gens.Length == 2
                    let pars = x.GetParameters()
                    where pars.Length == 2 && 
                        pars[0].ParameterType == typeof(IQueryable<>).MakeGenericType(gens[0]) &&
                        pars[1].ParameterType == typeof(Expression<>).MakeGenericType(typeof(Func<,>).MakeGenericType(gens))
                    select x).Single().MakeGenericMethod(typeof(SomeClass), typeof(string));

MethodCallExpression select2 = Expression.Call(null, select, Expression.Constant(queryable), lambda);

IQueryProvider provider = queryable.Provider;
IQueryable<string> q3 = provider.CreateQuery<string>(select2);


Lizenziert unter: CC-BY-SA with attribution
Nicht verbunden mit Stack Overflow
Ist diese KB legal? Ja, lerne warum
Lizenziert unter: CC-BY-SA with attribution
Nicht verbunden mit Stack Overflow
Ist diese KB legal? Ja, lerne warum