Dynamische MemberExpression

c# dynamic expression-trees linq

Frage

Ich möchte eine MemberExpression erstellen, die nur den Feldnamen kennt. z.B:

public static Expression<Func<TModel, T>> GenerateMemberExpression<TModel, T>(string fieldName)
    {
        PropertyInfo fieldPropertyInfo;

        fieldPropertyInfo = typeof(TModel).GetProperty(fieldName);

        var entityParam = Expression.Parameter(typeof(TModel), "e"); // {e}
        var columnExpr = Expression.MakeMemberAccess(entityParam, fieldPropertyInfo); // {e.fieldName}
        var lambda = Expression.Lambda(columnExpr, entityParam) as Expression<Func<TModel, T>>; // {e => e.column}

        return lambda;
    }

Das obige Problem besteht darin, dass der Feldtyp stark typisiert sein muss. Die Übergabe von "object" als Feldtyp funktioniert nicht. Gibt es eine Möglichkeit, dies zu generieren? Selbst Dynamic LINQ scheint nicht zu funktionieren.

Akzeptierte Antwort

Es gibt eine Reihe von Problemen mit Ihrem Code:

  1. Der Parameter für Ihre Methode heißt fieldName , aber Sie erhalten damit eine Eigenschaft heraus.
  2. Sie verwenden die nicht generische Expression.Lambda Methode, um den Ausdruck zu generieren, der möglicherweise einen unangemessenen Delegattyp auswählt, wenn das an die Methode übergebene Typargument T nicht mit dem Eigenschaftstyp übereinstimmt. In diesem Fall wird der as Befehl aus dem Ausdruck für den Rückgabetyp der Methode fehlschlagen und auf null ausgewertet. Lösung: Verwenden Sie die generische Lambda Methode mit den entsprechenden Typargumenten. Kein Casting erforderlich.
  3. Wenn Sie das zweite Problem lösen, werden die Dinge gut funktionieren, wenn eine sichere Referenzkonvertierung von der Eigenschaftstyp zu T verfügbar ist, aber nicht, wenn kompliziertere Konvertierungen wie Boxen / Heben erforderlich sind. Lösung: Verwenden Sie bei Bedarf die Expression.Convert Methode.

Im Folgenden finden Sie ein Update für Ihr Beispiel, das diese Probleme behebt:

public static Expression<Func<TModel, T>> GenerateMemberExpression<TModel, T>
   (string propertyName)
{
    var propertyInfo = typeof(TModel).GetProperty(propertyName);

    var entityParam = Expression.Parameter(typeof(TModel), "e"); 
    Expression columnExpr = Expression.Property(entityParam, propertyInfo);

    if (propertyInfo.PropertyType != typeof(T))
        columnExpr = Expression.Convert(columnExpr, typeof(T));

    return Expression.Lambda<Func<TModel, T>>(columnExpr, entityParam);
}

Dadurch werden alle folgenden Aufrufe erfolgreich ausgeführt:

GenerateMemberExpression<FileInfo, string>("Name");
GenerateMemberExpression<string, int>("Length");

// Reference conversion
GenerateMemberExpression<FileInfo, object>("Name");          

//Boxing conversion
GenerateMemberExpression<string, object>("Length");

//Lifted conversion
GenerateMemberExpression<string, int?>("Length");

Beliebte Antwort

Versuchen Sie, den Feldwert manuell zu konvertieren, wenn Sie ein "Objekt" übergeben. Beispielsweise:

var columnExpr = Expression.MakeMemberAccess(entityParam, fieldPropertyInfo); // {e.fieldName}
if (T.GetType().Equals(typeof(object)))
{
    columnExpr = Expression.Convert(columnExpr, typeof(object));
}

Hoffe das wird dir helfen.



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