'Argument expression is not valid' 动态创建匿名类型时
'Argument expression is not valid' when creating anonymous types dynamically
我正在为 return 自定义匿名类型创建表达式树构建器。我首先尝试使用离散类型,它工作正常,但是使用 TypeBuilder 在运行时构建类型并将该类型传递给表达式树失败并出现此错误
'Argument expression is not valid'
这是我使用的代码:
这个方法我用来创建匿名类型
private Type CreateAnonymousType(Dictionary<string, Type> properties)
{
AssemblyName dynamicAssemblyName = new AssemblyName("MyAssembly");
AssemblyBuilder dynamicAssembly = AssemblyBuilder.DefineDynamicAssembly(dynamicAssemblyName, AssemblyBuilderAccess.Run);
ModuleBuilder dynamicModule = dynamicAssembly.DefineDynamicModule("MyAssembly");
TypeBuilder dynamicAnonymousType = dynamicModule.DefineType("ReturnType", TypeAttributes.Public | TypeAttributes.Class | TypeAttributes.AutoClass);
foreach (var p in properties)
{
dynamicAnonymousType.DefineField(p.Key, p.Value, FieldAttributes.Public);
}
return dynamicAnonymousType.CreateType();
}
这是我创建表达式树的方法
var cars = new List<Car>();
for (int i = 0; i < 10; i++)
{
cars.Add(new Car { Id = i, Name = "Car " + i, Age = 2010 + i });
}
IQueryable<Car> allCars = cars.AsQueryable();
var properties = new Dictionary<string, Type>
{
{ "Id", typeof(int) },
{ "Name", typeof(string) }
};
ParameterExpression x = Expression.Parameter(typeof(Car), "x");
var listMembers = properties.Select(p => Expression.Property(x, p.Key));
var returnType = CreateAnonymousType(properties);
object destObject = Activator.CreateInstance(returnType);
var listBind = listMembers.Select(p => Expression.Bind(returnType.GetField(p.Member.Name), p));
var result = Expression.New(returnType);
var initExp = Expression.MemberInit(result, listBind.ToArray());
var call = Expression.Call(typeof(Queryable), "Select",
new Type[] {
typeof(Car),
returnType
}
, Expression.Constant(allCars)
, Expression.Lambda(initExp, x));
var qResult = allCars.Provider.CreateQuery<IdName>(call);
foreach (var car in qResult)
{
Console.WriteLine(car.Id + " - " + car.Name);
}
CreateQuery 方法执行时发生错误
这是因为 call
returns 是动态创建的 ReturnType
而不是 IdName
因此例外。此外,你不能将像 ReturnType
这样的动态类型作为泛型类型参数,因为编译器对它们一无所知,所以你应该使用 dynamic
来代替,这样类型将在运行时解析:
var qResult = allCars.Provider.CreateQuery<dynamic>(call);
我正在为 return 自定义匿名类型创建表达式树构建器。我首先尝试使用离散类型,它工作正常,但是使用 TypeBuilder 在运行时构建类型并将该类型传递给表达式树失败并出现此错误
'Argument expression is not valid'
这是我使用的代码:
这个方法我用来创建匿名类型
private Type CreateAnonymousType(Dictionary<string, Type> properties)
{
AssemblyName dynamicAssemblyName = new AssemblyName("MyAssembly");
AssemblyBuilder dynamicAssembly = AssemblyBuilder.DefineDynamicAssembly(dynamicAssemblyName, AssemblyBuilderAccess.Run);
ModuleBuilder dynamicModule = dynamicAssembly.DefineDynamicModule("MyAssembly");
TypeBuilder dynamicAnonymousType = dynamicModule.DefineType("ReturnType", TypeAttributes.Public | TypeAttributes.Class | TypeAttributes.AutoClass);
foreach (var p in properties)
{
dynamicAnonymousType.DefineField(p.Key, p.Value, FieldAttributes.Public);
}
return dynamicAnonymousType.CreateType();
}
这是我创建表达式树的方法
var cars = new List<Car>();
for (int i = 0; i < 10; i++)
{
cars.Add(new Car { Id = i, Name = "Car " + i, Age = 2010 + i });
}
IQueryable<Car> allCars = cars.AsQueryable();
var properties = new Dictionary<string, Type>
{
{ "Id", typeof(int) },
{ "Name", typeof(string) }
};
ParameterExpression x = Expression.Parameter(typeof(Car), "x");
var listMembers = properties.Select(p => Expression.Property(x, p.Key));
var returnType = CreateAnonymousType(properties);
object destObject = Activator.CreateInstance(returnType);
var listBind = listMembers.Select(p => Expression.Bind(returnType.GetField(p.Member.Name), p));
var result = Expression.New(returnType);
var initExp = Expression.MemberInit(result, listBind.ToArray());
var call = Expression.Call(typeof(Queryable), "Select",
new Type[] {
typeof(Car),
returnType
}
, Expression.Constant(allCars)
, Expression.Lambda(initExp, x));
var qResult = allCars.Provider.CreateQuery<IdName>(call);
foreach (var car in qResult)
{
Console.WriteLine(car.Id + " - " + car.Name);
}
CreateQuery 方法执行时发生错误
这是因为 call
returns 是动态创建的 ReturnType
而不是 IdName
因此例外。此外,你不能将像 ReturnType
这样的动态类型作为泛型类型参数,因为编译器对它们一无所知,所以你应该使用 dynamic
来代替,这样类型将在运行时解析:
var qResult = allCars.Provider.CreateQuery<dynamic>(call);