【问题标题】:How to invoke Func with without type arguments?如何在没有类型参数的情况下调用 Func?
【发布时间】:2014-04-28 17:35:09
【问题描述】:

请注意,我的逻辑太复杂了,我已经简化了一切以专注于这个问题。

我有函数字典,我必须调用它,但函数将类型 T 作为输入参数,它是派生类型,我没有访问权限,它在运行时可以是任何东西。如何调用它?

我收到以下错误,

Unable to cast object of type 
 'System.Func`2[DerivedClass,System.String]' to type    
 'System.Func`2[BaseClass,System.String]'.

我已经尝试过并且已经知道的替代方案,我正在寻找比以下替代方案更好的性能。

  1. 使用动态
  2. 重新创建表达式树,然后动态编译执行

这两种选择都非常昂贵,我需要更简单的方法。

这不是关于为什么我得到这个编译器错误的问题,或者我是否需要重新设计我的应用程序,当我已经说过我有两种调用 Func 的替代方案时,我正在寻找第三种更简单的替代方案(如果存在)

如何在无法访问 DerivedClass 的情况下调用 Func<DerivedClass,String>?我有一件物品。

class Program
{
    static void Main(string[] args)
    {

        object input = new DerivedClass();

        Func<BaseClass, string> f = null;

        Func<DerivedClass, string> a = s => s.ToString();

        object obj = a;

        // ERROR
        f = (Func<BaseClass, string>)obj;

        Console.WriteLine(f(input));

        Console.ReadLine();

    }
}


public class BaseClass {
    public override string ToString()
    {
        return "Base Class";
    }
}

public class DerivedClass : BaseClass {

    public override string ToString()
    {
        return "Derived Class";
    }

}

【问题讨论】:

  • 您的问题中“我确实有权访问”是什么意思?
  • @YuvalItzchakov 我写过我无权访问该类型,我的代码是通用库的一部分,它在另一个项目中使用。所以在运行时,我将有任何函数,我只需要调用它。

标签: c# lambda func


【解决方案1】:

你在这里尝试做的事情没有任何意义。假设您有一个类 A,以及从它继承的两个类 B 和 C。

如果您能够按照您在此处所说的进行操作,那么将函数 Func&lt;B, string&gt; 转换为 Func&lt;A, string&gt; 将意味着您获得的函数也可以将 C 的实例作为参数,因为 C 也继承来自A。

事实上,你可以更进一步说,因为一切都继承自对象,你可以将任何函数转换为Func&lt;object, string&gt;,然后将任何你想要的作为参数传入。

【讨论】:

    【解决方案2】:

    让我们暂时摆脱委托,并根据它们抽象出的方法来考虑这一点。考虑以下Foo 方法:

    public static void Foo(int i)
    {
        Console.WriteLine(i + 2);
    }
    

    现在我们有了另一个方法Bar。它接受object。我们想在参数上调用Foo

    public static void Bar(object o)
    {
        Foo(o);
    }
    

    当然,这行不通。我们无法知道提供的对象实际上是int

    这通常意味着以下两种情况之一:

    1. 您实际上并不想这样做;您无法知道更通用的参数实际上将是正确的更派生参数的实例;你应该重新设计你的应用程序。

    2. 您知道一些编译器不知道的东西,虽然编译器无法验证此约束是否正确,但无论出于何种原因,它实际上在运行时都是有效的。既然你知道它不会失败,你可以使用强制类型转换来通知编译器,并将类型检查推迟到运行时。

    如果你碰巧在第二个位置,而不是第一个位置,你可以添加强制转换,而不是通过强制转换委托,而是通过创建一个新方法(可能通过 lambda)对参数执行强制转换然后调用另一个委托:

    Func<DerivedClass, string> derivedSelector = derived => derived.ToString();
    
    Func<BaseClass, string> baseSelector = s => derivedSelector((DerivedClass)s);
    

    【讨论】:

      猜你喜欢
      • 2015-01-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-10-13
      相关资源
      最近更新 更多