C# 生成对应于Enumerable.Cast的已编译委托<;T>;?
这是一个非常棘手的问题,我在调用泛型方法(C# 生成对应于Enumerable.Cast的已编译委托<;T>;?,c#,reflection,expression-trees,C#,Reflection,Expression Trees,这是一个非常棘手的问题,我在调用泛型方法(MethodInfo)时遇到了麻烦,该方法是由表达式树上下文中的另一个MethodCallExpression(通过使用MakeGenericMethod)返回的 从技术上讲,我想要的编译委托如下所示: Func<IEnumerable, Type, IEnumerable> cast; 所以,正如你所看到的,这是一个非常棘手的问题,以前从未遇到过这样的问题。我知道我可以通过调用castMethod(作为MethodCallExpressi
MethodInfo
)时遇到了麻烦,该方法是由表达式树上下文中的另一个MethodCallExpression
(通过使用MakeGenericMethod
)返回的
从技术上讲,我想要的编译委托如下所示:
Func<IEnumerable, Type, IEnumerable> cast;
所以,正如你所看到的,这是一个非常棘手的问题,以前从未遇到过这样的问题。我知道我可以通过调用
castMethod
(作为MethodCallExpression
)来解决这个问题。这样,我需要获得MethodInfo
的Invoke
方法,并使用Expression.Call
在实例castMethod
上调用该方法。但是等等,如果是这样的话,我们仍然使用方法。调用,就像我们使用反射
来编写代码,而通常不编译它?我真的相信表达式有一些隐藏的魔力。Call
比MethodInfo做得不同(更好更快)。Invoke
你试图做的事情完全没有意义,而且与Enumerable.Cast
非常不同,后者实际上做了一些有用的事情
让我们看看后者的定义:
IEnumerable<T> Cast<T>(this IEnumerable source);
IEnumerable Cast(this IEnumerable items, Type type);
这将获取一个非类型化的可枚举项,并返回一个非类型化的可枚举项。它在内部所做的并不重要,因为即使它按您想要的方式工作,您从中得到的仍然是可枚举的纯对象
s,因此要使用这些值,您仍然需要正确地强制转换这些值(并取消装箱值类型的装箱)。你什么也没得到,你已经有了这样一个集合——你首先传递给你函数的东西
即使您使用编译表达式的缓存(每种类型一个)使强制转换工作,这并不困难,但输出仍然会通过返回类型强制转换回对象。您尝试执行的操作完全没有意义,并且与Enumerable.cast非常不同,后者实际上做了一些有用的事情
让我们看看后者的定义:
IEnumerable<T> Cast<T>(this IEnumerable source);
IEnumerable Cast(this IEnumerable items, Type type);
这将获取一个非类型化的可枚举项,并返回一个非类型化的可枚举项。它在内部所做的并不重要,因为即使它按您想要的方式工作,您从中得到的仍然是可枚举的纯对象
s,因此要使用这些值,您仍然需要正确地强制转换这些值(并取消装箱值类型的装箱)。你什么也没得到,你已经有了这样一个集合——你首先传递给你函数的东西
即使使用编译表达式的缓存(每种类型一个)使强制转换工作,这并不困难,但输出仍然会通过返回类型强制转换回对象。类型必须在编译表达式时知道。它不能是已编译委托的输入。如果您编写的方法接受类型
并返回Func
(即内部调用.Cast()
,其中T
是您传入的类型的委托),则可以执行该操作work@canton7如果是这样的话,对我来说太容易了,这样做并没有带来太多好处。我们事先有很多未知的类型
(目标施法类型)。因此,我们需要为每种类型构建每个委托并将其全部缓存?如果无法做到这一点,我希望每次都直接使用反射,尽可能多地使用缓存,并基于MethodInfo.Invoke
的速度,这并不是很糟糕,但当然也不比编译委托好。是的。当然,另一种选择是使用反射调用Cast。但是,我不确定你能得到多少好处?你只能真正做参考conversions@canton7我认为最昂贵的操作涉及MethodInfo.Invoke
,因此我试图避免它。Type
必须在编译表达式时知道。它不能是已编译委托的输入。如果您编写的方法接受类型
并返回Func
(即内部调用.Cast()
,其中T
是您传入的类型的委托),则可以执行该操作work@canton7如果是这样的话,对我来说太容易了,这样做并没有带来太多好处。我们事先有很多未知的类型
(目标施法类型)。因此,我们需要为每种类型构建每个委托并将其全部缓存?如果无法做到这一点,我希望每次都直接使用反射,尽可能多地使用缓存,并基于MethodInfo.Invoke
的速度,这并不是很糟糕,但当然也不比编译委托好。是的。当然,另一种选择是使用反射调用Cast。但是,我不确定你能得到多少好处?你只能真正做参考conversions@canton7我认为最昂贵的操作涉及MethodInfo.Invoke
,因此我试图避免它。您对IEnumerable强制转换(这个IEnumerable项,类型)
的假设是错误的,当然我们不会像往常一样在代码中明确使用它,我们在反射
的上下文中使用它,输入的项
和返回的IEnumerable
的值完全不同(例如,您可以调用GetType
来了解差异)。items
类型无法在其他方法中传递,因此我们需要在此处执行Cast
。所有操作都是使用反射(和表达式
)完成的,没有强类型。是什么让您认为强制转换引用类型会改变其GetType
类型?这是一个虚拟函数,转换引用类型不会更改其虚拟接口。我们不会转换整个项,而是对每个项进行转换。因此,不是将IEnumerable
作为输入,而是将IEnumerable
作为输出。这只是一个简单的例子。相信我,我做了大量的反射,没有这样的转换
,代码只会在运行时出错。使用Cast
,它可以工作。那你觉得呢