gpt4 book ai didi

c# - 从反射转向表达式树

转载 作者:行者123 更新时间:2023-12-02 04:12:19 24 4
gpt4 key购买 nike

我有一个反射代码,用于创建 List<> 的实例(类型参数在运行时已知),并调用Add方法向其添加一些值。我的代码片段是这样的:

// here is my type parameter
var genericType = typeof(MyRunTimeType);
// here is a list of my values
MyRunTimeType[] values = MyRunTimeValuesOfTypeMyRunTimeType();

// creating instance of List<>
var listType = typeof(List<>);
var listGenericType = listType.MakeGenericType(genericType);
var listInstance = Activator.CreateInstance(listGenericType);

// getting Add method and call it
var addMethod = listGenericType.GetMethod("Add", genericType);
foreach (var value invalues)
addMethod.Invoke(listInstance, new[] { value });

那么,您建议如何将此反射片段转换为表达式树?

更新:

嗯,我写了这个片段,它似乎无法工作:

public static Func<IEnumerable<object>, object> GetAndFillListMethod(Type genericType) {

var listType = typeof(List<>);
var listGenericType = listType.MakeGenericType(genericType);

var values = Expression.Parameter(typeof(IEnumerable<>).MakeGenericType(genericType), "values");

var ctor = listGenericType.GetConstructor(BindingFlags.Instance | BindingFlags.Public, null, new Type[0], null);
var instance = Expression.Parameter(listGenericType, "list");

var assign = Expression.Assign(instance, Expression.New(ctor));

var addMethod = listGenericType.GetMethod("AddRange", new[] { typeof(IEnumerable<>).MakeGenericType(genericType) });

var addCall = Expression.Call(instance, addMethod, new Expression[] { values });

var block = Expression.Block(
new[] { instance },
assign,
addCall,
Expression.Convert(instance, typeof(object))
);

return (Func<IEnumerable<object>, object>)Expression.Lambda(block, values).Compile();
}

但是,我收到此错误:

Unable to cast object of type 
'System.Func`2[System.Collections.Generic.IEnumerable`1[System.String],System.Object]'
to type
'System.Func`2[System.Collections.Generic.IEnumerable`1[System.Object],System.Object]'.

请问有什么建议吗?

最佳答案

工作:

public static Func<IEnumerable<object>, object> GetAndFillListMethod(Type genericType)
{
var listType = typeof(List<>);
var listGenericType = listType.MakeGenericType(genericType);

var values = Expression.Parameter(typeof(IEnumerable<object>), "values");

var ctor = listGenericType.GetConstructor(BindingFlags.Instance | BindingFlags.Public, null, new Type[0], null);

// I prefer using Expression.Variable to Expression.Parameter
// for internal variables
var instance = Expression.Variable(listGenericType, "list");

var assign = Expression.Assign(instance, Expression.New(ctor));

var addMethod = listGenericType.GetMethod("AddRange", new[] { typeof(IEnumerable<>).MakeGenericType(genericType) });

// Enumerable.Cast<T>
var castMethod = typeof(Enumerable).GetMethod("Cast", new[] { typeof(IEnumerable) }).MakeGenericMethod(genericType);

// For the parameters there is a params Expression[], so no explicit array necessary
var castCall = Expression.Call(castMethod, values);
var addCall = Expression.Call(instance, addMethod, castCall);

var block = Expression.Block(
new[] { instance },
assign,
addCall,
Expression.Convert(instance, typeof(object))
);

return (Func<IEnumerable<object>, object>)Expression.Lambda(block, values).Compile();
}

您的问题在于您试图返回 Func<IEnumerable<object>, object>但你的功能实际上是 Func<IEnumerable<T>, object> 。解决办法就是将参数设为 IEnumerable<object>然后使用 Enumerable.Cast<T>在传递到 AddRange 之前

我已经更改了Expression.Parameter用于instanceExpression.Variable ...但这只是为了更清楚地表明它是一个变量,而不是一个参数。 Expression.Variable生成的表达式树和 Expression.Parameter是相同的(因为两个函数具有相同的代码)。使用它的上下文定义了它是参数还是变量。我又做了一个小改动:Expression.Call不需要参数的显式数组初始化。

啊...请注意 Block 的最后一行可能是:

addCall,
instance

而不是

addCall,    
Expression.Convert(instance, typeof(object))

因为任何引用类型都可以隐式转换为 object .

关于c# - 从反射转向表达式树,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35913495/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com