参数类型不匹配 Transforming anonymous Expression<Func<T,U>> to non anonymous Expression<Func<T,U>>
Argument types do not match Transforming anonymous Expression<Func<T,U>> to non anonymous Expression<Func<T,U>>
假设我们有三个这样的 类:
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.ColSubs.Select(...)
时,出现以下错误:
System.ArgumentException: Argument types do not match
以下是您需要添加到递归 Transform
方法的代码,该方法 恰好 处理该场景,即检测 Select
方法,转换 selector
参数,修改 Select
的 TResult
泛型类型参数并用新的 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);
}
假设我们有三个这样的 类:
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.ColSubs.Select(...)
时,出现以下错误:
System.ArgumentException: Argument types do not match
以下是您需要添加到递归 Transform
方法的代码,该方法 恰好 处理该场景,即检测 Select
方法,转换 selector
参数,修改 Select
的 TResult
泛型类型参数并用新的 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);
}