我有以下表达式:
.Call System.Linq.Queryable.Select(
.Constant<System.Linq.EnumerableQuery`1[System.Linq.Dynamic.Tests.Helpers.User]>(System.Linq.Dynamic.Tests.Helpers.User[]),
'(.Lambda #Lambda1<System.Func`2[System.Linq.Dynamic.Tests.Helpers.User,System.Linq.Dynamic.DynamicObjectClass]>))
.Lambda #Lambda1<System.Func`2[System.Linq.Dynamic.Tests.Helpers.User,System.Linq.Dynamic.DynamicObjectClass]>(System.Linq.Dynamic.Tests.Helpers.User $var1)
{
.New System.Linq.Dynamic.DynamicObjectClass(
.New System.Collections.Generic.KeyValuePair`2[System.String, System.Object](
"UserName",
(System.Object)$var1.UserName),
.New System.Collections.Generic.KeyValuePair`2[System.String, System.Object](
"MyFirstName",
(System.Object)($var1.Profile).FirstName))
}
并希望将其重写为以下内容:
.Call System.Linq.Queryable.Select(
.Constant<System.Linq.EnumerableQuery`1[System.Linq.Dynamic.Tests.Helpers.User]>(System.Linq.Dynamic.Tests.Helpers.User[]),
'(.Lambda #Lambda1<System.Func`2[System.Linq.Dynamic.Tests.Helpers.User,DynamicClass1]>))
.Lambda #Lambda1<System.Func`2[System.Linq.Dynamic.Tests.Helpers.User,DynamicClass1]>(System.Linq.Dynamic.Tests.Helpers.User $var1)
{
.New DynamicClass1()
{
UserName = $var1.UserName,
MyFirstName = ($var1.Profile).FirstName
}
}
我尝试使用表达式访问者并遵循代码:
protected override Expression VisitNew(NewExpression node)
{
if (node.Type == typeof(DynamicObjectClass))
{
var properties = new List<DynamicProperty>(node.Arguments.Count);
var expressions = new List<Expression>(node.Arguments.Count);
foreach (NewExpression newEx in node.Arguments)
{
var name = ((ConstantExpression)newEx.Arguments.First()).Value as string;
var parameter = ((UnaryExpression)newEx.Arguments.Skip(1).First()).Operand;
properties.Add(new DynamicProperty(name, parameter.Type));
expressions.Add(parameter);
}
Type type = DynamicExpression.CreateClass(properties);
MemberBinding[] bindings = new MemberBinding[properties.Count];
for (int i = 0; i < bindings.Length; i++)
bindings[i] = Expression.Bind(type.GetProperty(properties[i].Name), expressions[i]);
return Expression.MemberInit(Expression.New(type), bindings);
}
return base.VisitNew(node);
}
但我得到了这个例外:
类型&#39; System.ArgumentException&#39;的第一次机会异常。发生了 在System.Core.dll
中其他信息:表达类型&#39; DynamicClass1&#39;不可能是 用于返回类型&#39; System.Linq.Dynamic.DynamicObjectClass&#39;
我想我需要覆盖VisitLambda,但我没有确切的想法!任何人都可以帮助我吗?
答案 0 :(得分:1)
使用此代码,它现在可以正常运行 (但我不认为它适用于所有情况......)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;
namespace System.Linq.Dynamic
{
public static class ExpressionConverter
{
private static ExpressionConverterVisitor visitor = new ExpressionConverterVisitor();
public static Expression DynamicObjectClassToAnonymousType(this Expression expression)
{
return visitor.Visit(expression);
}
private class ExpressionConverterVisitor : ExpressionVisitor
{
protected override Expression VisitLambda<T>(Expression<T> node)
{
if (node.Body is NewExpression && ((NewExpression)node.Body).Type == typeof(DynamicObjectClass))
{
var e = node.Body as NewExpression;
var properties = new List<DynamicProperty>(e.Arguments.Count);
var expressions = new List<Expression>(e.Arguments.Count);
foreach (NewExpression newEx in e.Arguments)
{
var name = ((ConstantExpression)newEx.Arguments.First()).Value as string;
var parameter = ((UnaryExpression)newEx.Arguments.Skip(1).First()).Operand;
properties.Add(new DynamicProperty(name, parameter.Type));
expressions.Add(parameter);
}
Type type = DynamicExpression.CreateClass(properties);
MemberBinding[] bindings = new MemberBinding[properties.Count];
for (int i = 0; i < bindings.Length; i++)
bindings[i] = Expression.Bind(type.GetProperty(properties[i].Name), expressions[i]);
var membInit = Expression.MemberInit(Expression.New(type), bindings);
var typeOfTArgs = typeof(T).GetGenericArguments();
var funcTType = typeof(Func<,>).MakeGenericType(new[] { typeOfTArgs.First(), type });
var mi = typeof(Expression).GetMethods().FirstOrDefault(x => x.Name == "Lambda" && x.ContainsGenericParameters);
MethodInfo genericMethod = mi.MakeGenericMethod(new[] { funcTType });
var lambda = genericMethod.Invoke(null, new object[] { membInit, node.Parameters.ToArray() }) as Expression;
return lambda;
}
return base.VisitLambda<T>(node);
}
protected override Expression VisitMethodCall(MethodCallExpression node)
{
if (node.Method.Name == "Select")
{
var arguments = node.Arguments.ToList();
for (int n = 0; n < arguments.Count; n++)
arguments[n] = visitor.Visit(arguments[n]);
var typeList = arguments.Select(x => x.Type).ToArray();
var funcTType = typeof(Func<,>).MakeGenericType(typeList);
var argsmth = node.Method.GetGenericArguments().ToArray();
argsmth[1] = ((LambdaExpression)((UnaryExpression)arguments[1]).Operand).Body.Type;
var mi = node.Method.DeclaringType.GetMethods().FirstOrDefault(x => x.Name == "Select");
var mth = mi.MakeGenericMethod(argsmth);
return Expression.Call(mth, arguments);
}
return base.VisitMethodCall(node);
}
}
}
}