我有一个
Expression<Func<T1, T2>> source
因此我可以毫无问题地将其编译为Func<T1, T2>
:
Func<T1, T2> result = source.Compile();
但是现在我有一个特殊情况,其中(给定T2是一个整数)我必须返回一个Func<T1, int>
。当然,我不能只转换它,但也找不到其他方法来转换它。
public Func<T1, int> GetFuncToReturnId()
{
if (source.ReturnType != typeof(int))
{
throw new InvalidOperationException("source must be of return type must be of type int");
}
return // ??? please help !!!
}
我尝试将Expression或编译后的Func的部分转移到Func<T1, int>
的构造函数中,但这没有帮助。我该怎么办
Expression<Func<T1, T2>>
转换为Expression<Func<T1, int>>
Func<T1, T2>
到Func<T1, int>
?答案 0 :(得分:3)
不清楚您的问题是什么问题,但我可以猜测是将Func<T1, T2>
转换为Func<T1, int>
会导致无效的转换错误。
这是无效的原因是因为C#对于从类型参数到任何其他类型的任何转换都比较保守。假设您具有从Foo到Bar的用户定义的转换。如果您有方法
Bar M<T>(T t) { return (Bar)t; }
那么您可能会合理地期望M<Foo>(new Foo())
会将用户定义的转换称为Bar
。但是C#泛型不是模板,并且不会为每个泛型实例重新生成代码。仅当存在 identity 或 reference 转换并且C#阻止您犯此常见错误时,这种转换才有效。
此外,每当您对通用类型进行类型测试时,就不再是“通用” 。不管类型参数如何,通用代码都应该工作相同,这就是为什么它被称为“通用代码”的原因。听起来您正在做的事情是针对泛型的目的。
也就是说,如果您不愿意这样做,可以通过以下几种方法在通用类型之间进行引用转换:
class C<T1, T2>
{
void M(Func<T1, int> f) {}
// This way is wrong.
void N1(Func<T1, T2> f)
{
if (f is Func<T1, int>)
M((Func<T1, int>)f); // Error, cannot convert
}
// This works.
void N2(Func<T1, T2> f)
{
var fi = f as Func<T1, int>;
if (fi != null)
M(fi);
}
// This also works.
void N3(Func<T1, T2> f)
{
if (f is Func<T1, int>)
M((Func<T1, int>)(object)f);
}
// This works in C# 7; it's a more concise way to combine the previous two
void N4(Func<T1, T2> f)
{
if (f is Func<T1, int> fi)
M(fi);
}
}
答案 1 :(得分:1)
您可以使用Convert.ChangeType
var compiled = source.Compile();
return (T1 x) => (int) Convert.ChangeType(compiled(x), typeof(int));
或简单地投射两次
var compiled = source.Compile();
return (T1 x) => (int) (object) compiled(x);