Работа с «преобразованием в объект» в MemberExpression

#c# #reflection #linq-expressions

#c# #отражение #linq-выражения

Вопрос:

У меня есть класс, который выглядит следующим образом:

 public class MyClass
{
  public int Id { get; set; }
  public string Name { get; set; }
}
 

Мне нужно сделать это:

 var memberExpressions = ConvertToMemberExpressions<MyClass>(o => o.Id, o => o.Name);

...

public static List<MemberExpression> ConvertToMemberExpressions<T>(params Expression<Func<T, object>>[] methodExpressions)
{
    var results = new List<MemberExpression>();
    foreach(var methodExpression in methodExpressions)
    {
        var memberExpression = methodExpression.Body as MemberExpression;
        results.Add(memberExpression);
    }
    return results;
}
 

Проблема в том, что из-за Func<T, object> (чтобы иметь возможность включать оба int параметра и string в качестве параметров) мое MethodExpression выглядит так: {o => Convert(o.Id, Object)} , что мне не нужно. Мне нужно достичь o.Id .

Этого не происходит со строками: {o => o.Name} , здесь нет преобразования.

Я использую Func<T,object> , чтобы иметь возможность использовать Intellisense и получать доступ к реквизитам MyClass. Я пытался использовать Func<T, dynamic> вместо этого, но результат тот же.

Это можно решить с помощью нескольких перегрузок:

 public static ConvertToMemberExpressions<TClass, T1>(Expression<Func<TClass,T1>>[] methodExpression1)
public static ConvertToMemberExpressions<TClass, T1, T2>(Expression<Func<TClass,T1>>[] methodExpression1, Expression<Func<TClass,T2>>[] methodExpression2)
...
 

…но это жертва, которой я хотел бы избежать, если это возможно.


Вопрос:

Возможно ли построить o => o.Id из o => Convert(o.Id, Object) ?

Ответ №1:

Просто проверьте, является ли ваш methodExpression.Body a UnaryExpression с a NodeType из Convert :

 public static List<MemberExpression> ConvertToMemberExpressions<T>(params Expression<Func<T, object>>[] methodExpressions)
{
    var results = new List<MemberExpression>();
    foreach (var methodExpression in methodExpressions)
    {
        var expr = methodExpression.Body;
        if (expr is UnaryExpression unaryExpression amp;amp; unaryExpression.NodeType == ExpressionType.Convert)
        {
            expr = unaryExpression.Operand;
        }

        if (expr is MemberExpression memberExpression)
        {
            results.Add(memberExpression);
        }
        else
        {
            throw new ArgumentException($"Unexpected expression type {expr.NodeType}");
        }
    }
    return results;
}
 

При работе с выражениями отладчик — ваш друг:

Изображение окна просмотра в expr, показывающее тип и значения для nodeType и операнда

Комментарии:

1. Большое спасибо, это кажется правильным решением. Я, вероятно, слишком много думал об этом … unaryExpression.Operand все время был у меня перед глазами, но я думал, что не смогу использовать его как MemberExpression, поди разберись. Еще раз спасибо.