通用委托投射

时间:2018-02-10 01:37:20

标签: c# generics casting delegates

[edit]以下适用于C#

public class C {
    public void M() {
        Func<int,string> a = intArg => "helloWorld"; // string:object
        Test(a);
        Func<int,C> b = intArg => new C(); // C:object
        Test(b);
    }
    public void Test(Func<int,object> arg){
        Console.WriteLine(arg(1).ToString());
    }
}

如何使用自我声明的委托实现相同的目标?

public class C {
    public delegate Y MyDelegate<X,Y>(X input);
    public void M() {
        MyDelegate<int,string> a = intArg => "helloWorld"; // cannot convert from 'C.MyDelegate<int, string>' to 'C.MyDelegate<int, object>' 
        Test(a);
        MyDelegate<int,C> b = intArg => new C(); // cannot convert from 'C.MyDelegate<int, C>' to 'C.MyDelegate<int, object>'
        Test(b);
    }
    public void Test(MyDelegate<int,object> arg){
        Console.WriteLine(arg(1).ToString());
    }
}

据我所知,编译器无法判断哪个类型的参数是参数(逆变),哪个是返回值(协方差),也许有办法指定它?

[更新] 我找到了解决方案:
public delegate Y MyDelegate<X,out Y>(X input);

1 个答案:

答案 0 :(得分:0)

当你这样称呼时:

object delegateArg = genericMethod.Invoke();

返回值 - delegateArg - 是Func<int, something>,其中something可以是任何内容。然后你想将Func<int, ???>传递给另一个可能会调用它的方法。

您可以将它传递给期望Func<int, object>的方法,并且除非第二个泛型参数是值类型,否则它将编译。当您调用它时,您将获得调用的结果为object。结果的实际类型将是第二个未知泛型参数。

但是如果你不知道第二个通用参数是什么,那么你传递给它的方法也不会知道。它能找到的唯一方法是使用反射,检查类型,并获得第二个通用参数。

因此,您可以传递Func<int, object>并进行一些反思,以确定object实际上是string。或者你可以只调用函数,得到结果,并检查返回值的类型,并确定它是string

最大的问题是,如果您还不知道自己将要获得什么类型,那么您怎么知道自己想要做什么?如果你不知道什么类型的genericMethod.Invoke将更加确定,那么你怎么知道你想要它?

这有点像去商店购买壁挂式支架,除非你不知道你想要挂在墙上的是什么。但如果你不知道你想要装的是什么,那你为什么要到商店购买壁挂支架?

有时候有充分的理由,但这通常是当我们有函数返回非特定的东西然后将它们传递给其他方法时会发生的事情。如果我们能够解决它以便我们的代码是强类型的,那就好多了。我们调用一个返回某个类型的方法,因为我们需要一个该类型的对象。然后我们将该东西传递给另一个期望该类型并且具有特定用途的方法。

有些例外情况我们并不关心某事物的类型,但它并不常见,因为我们通常不会编写不符合的代码做一些特定的事情。除非我们确定我们真的不关心实际类型是什么,否则重新审视我们的方法并找到一种强力输入的方法是件好事。这可能涉及使用泛型或在某些情况下编写更多的类或方法而不是处理各种输入的类。