如何将 Func<T1,T2> 转换或转换为 Func<T1,int>
How to convert or cast a Func<T1,T2> to a Func<T1,int>
我有一个
Expression<Func<T1, T2>> source
所以我可以毫无问题地将它编译成 Func<T1, T2>
:
Func<T1, T2> result = source.Compile();
但现在我有一个特殊情况,其中(给定 T2 是一个整数)我必须 return 一个 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>
?
您可以使用 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);
从你的问题中不清楚你遇到的问题到底是什么,但我可以猜测是将 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# 可防止您犯这种常见错误。
此外,任何时候您对泛型进行类型测试时,它不再是"generic"。通用代码应该以相同的方式工作 ,而不管类型参数如何 ,这就是它被称为 "generic code" 的原因。听起来你正在做的事情违背了泛型的目的。
就是说,如果您执意要这样做,有几种方法可以像这样在泛型类型之间进行引用转换:
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);
}
}
我有一个
Expression<Func<T1, T2>> source
所以我可以毫无问题地将它编译成 Func<T1, T2>
:
Func<T1, T2> result = source.Compile();
但现在我有一个特殊情况,其中(给定 T2 是一个整数)我必须 return 一个 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>
?
您可以使用 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);
从你的问题中不清楚你遇到的问题到底是什么,但我可以猜测是将 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# 可防止您犯这种常见错误。
此外,任何时候您对泛型进行类型测试时,它不再是"generic"。通用代码应该以相同的方式工作 ,而不管类型参数如何 ,这就是它被称为 "generic code" 的原因。听起来你正在做的事情违背了泛型的目的。
就是说,如果您执意要这样做,有几种方法可以像这样在泛型类型之间进行引用转换:
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);
}
}