如何将Func <t1,t2>转换或转换为Func <t1,int>

时间:2018-10-25 13:17:05

标签: c# func

我有一个

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>

2 个答案:

答案 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);