Типы аргументов не соответствуют Преобразованию анонимного выражения> к неанонимному выражению> - PullRequest
1 голос
/ 23 апреля 2019

Представьте, что у нас есть три класса, подобных этому:

public class ParentType {
    private ParentType() {}

    public int Id { get; protected set; }
    public SubType Sub { get; protected set; }
}

public class SubType{
    private SubType(){}

    public int Id { get; protected set; }
    public ICollection<ColSubType> ColSubs{get; protected set;}
}

public class ColSubType{
    private ColSubType(){}

    public int Id { get; protected set; }
    public SubType SubType { get; set; }
}

У меня есть анонимное выражение вроде этого:

x => new
{
   x.Id,
   Sub = new
   {
      x.Sub.Id,
      ColSubs = x.Sub.ColSubs.Select(u=> new {
             u.Id
      }).ToList()
   }
}

Мне нужно преобразовать его в неанонимное выражение, подобное этому:

x => new ParentType()
{
   Id = x.Id,
   Sub = new SubType()
   {
      Id = x.Sub.Id,
      ColSubs = x.Sub.ColSubs.Select(u=> new ColSubs(){
             Id = u.Id
      }).ToList()
   }
}

Благодаря ответу @ IvanStoev на этот вопрос: Переменная 'x.Sub' типа 'SubType' ссылается из области действия ', но она не определена ошибка Я могупреобразовать простые выражения, но когда я добавляю x.Sub.ColSubs.Select(...), я получаю следующую ошибку:

System.ArgumentException: типы аргументов не совпадают

1 Ответ

2 голосов
/ 23 апреля 2019

Ниже приведен код, который необходимо добавить к рекурсивному методу Transform, который обрабатывает точно этот сценарий, т. Е. Метод обнаружения Select, преобразование аргумента selector, изменение универсального TResult введите аргумент Select и вызовите его с новым selector, и, наконец, вызовите ToList в случае, если пункт назначения не IEnumerable<T>:

if (source.Type != type && source is MethodCallExpression call && call.Method.IsStatic
    && call.Method.DeclaringType == typeof(Enumerable) && call.Method.Name == nameof(Enumerable.Select))
{
    var sourceEnumerable = call.Arguments[0];
    var sourceSelector = (LambdaExpression)call.Arguments[1];
    var sourceElementType = sourceSelector.Parameters[0].Type;
    var targetElementType = type.GetGenericArguments()[0];
    var targetSelector = Expression.Lambda(
        Transform(sourceSelector.Body, targetElementType),
        sourceSelector.Parameters);
    var targetMethod = call.Method.GetGenericMethodDefinition()
        .MakeGenericMethod(sourceElementType, targetElementType);
    var result = Expression.Call(targetMethod, sourceEnumerable, targetSelector);
    if (type.IsAssignableFrom(result.Type)) return result;
    return Expression.Call(
        typeof(Enumerable), nameof(Enumerable.ToList), new[] { targetElementType },
        result);
}
...