Ausdruck aus String erstellen (Nullreferenz)

c# expression expression-trees generics sql-order-by

Frage

Hier ist das Problem:

Wir verwenden ein Tabellenobjekt, um den Benutzern einige Funktionen wie Suchen, Sortieren, Seitenumbruch usw. zu ermöglichen. Diese Tabellen funktionieren hervorragend. Aber es gibt ein Problem mit einer der Funktionen: Die Sortierung (= OrderBy).

Um die Sortierung zu ermöglichen, setzen wir in jeder Spalte eine Zeichenfolge, die den Ausdruck darstellt: Wenn der Ausdruck beispielsweise Person => Person.Id ist, lautet die Zeichenfolge ID; Wenn der Ausdruck Person => Person.Address.Street ist, lautet die Zeichenfolge Address.Street.

Im ersten Fall (Person => Person.Id) funktioniert es großartig, da es kein Unterobjekt ist. Aber im zweiten Fall (Person => Person.Address.Street) ist dies nicht der Fall, da das Address-Objekt null sein könnte.

Um zu ermöglichen, dass der Orderby von einem String ausgeführt wird, habe ich in einem anderen Post die folgenden Methoden gefunden:

public static IOrderedQueryable<T> OrderBy<T>(this IQueryable<T> source, string property)
{
    return ApplyOrder<T>(source, property, "OrderBy");
}

public static IOrderedQueryable<T> OrderByDescending<T>(this IQueryable<T> source, string property)
{
    return ApplyOrder<T>(source, property, "OrderByDescending");
}

public static IOrderedQueryable<T> ThenBy<T>(this IOrderedQueryable<T> source, string property)
{
    return ApplyOrder<T>(source, property, "ThenBy");
}

public static IOrderedQueryable<T> ThenByDescending<T>(this IOrderedQueryable<T> source, string property)
{
    return ApplyOrder<T>(source, property, "ThenByDescending");
}

private static IOrderedQueryable<T> ApplyOrder<T>(IQueryable<T> source, string property, string methodName)
{
    string[] props = property.Split('.');
    Type type = typeof(T);
    ParameterExpression arg = Expression.Parameter(type, "x");
    Expression expr = arg;
    foreach (string prop in props)
    {
        // use reflection (not ComponentModel) to mirror LINQ 
        PropertyInfo pi = type.GetProperty(prop);
        expr = Expression.Property(expr, pi);
        type = pi.PropertyType;
    }
    Type delegateType = typeof(Func<,>).MakeGenericType(typeof(T), type);
    LambdaExpression lambda = Expression.Lambda(delegateType, expr, arg);
    object result = typeof(Queryable).GetMethods().Single(
    method => method.Name == methodName
        && method.IsGenericMethodDefinition
        && method.GetGenericArguments().Length == 2
        && method.GetParameters().Length == 2)
            .MakeGenericMethod(typeof(T), type)
            .Invoke(null, new object[] { source, lambda });
    return (IOrderedQueryable<T>)result;
}

Hat jemand von euch eine Idee, die mir erlauben würde, eine Bedingung hinzuzufügen, die das Objekt nicht mit Unterobjekt == null auswählt? Oder verhindern, dass versucht wird, von einem Objekt, das null ist, auf eine Eigenschaft zuzugreifen?

EDIT:

Der Check würde etwa wie folgt aussehen: list.OrderBy (x => (x.Address! = Null)? X.Address.Street: string.Empty).

Also muss ich ein Null-Check für jedes Objekt zwischen x und dem letzten Feld hinzufügen. Ist es möglich, das mit diesen Methoden zu tun?

EDIT 2:

Ich habe versucht zu ersetzen

Expression.Property(expr, pi);

durch

expr = Expression.Condition(
                Expression.Equal(expr, Expression.Constant(null)),
                Expression.Constant(String.Empty),
                Expression.Property(expr, pi));

Aber es scheint, dass es nicht funktioniert. Ich bekomme folgende Ausnahme:

Argument types do not match

Irgendeine Idee, wie ich den Standardwert für das Feld wissen sollte, auf das expr zugreift?

Beliebte Antwort

Erstellen Sie Ihre Nullkonstante als Eigenschaftstyp.

expr = Expression.Condition(Expression.Equal(expr, Expression.Constant(null, expr.Type)),
                Expression.Constant(String.Empty),
                Expression.Property(expr, pi));


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