与Func <in t1,=“”out =“”tresult =“”>的Co / contravariance作为参数

时间:2016-02-18 11:51:43

标签: c# .net generics generic-variance

假设我有一个界面,例如

public interface IInterface<in TIn, out TOut> {
  IInterface<TIn, TOut> DoSomething(TIn input);
}

TIn contra -variant,TOut co <​​/ em> -variant。

现在,我希望调用者能够指定一些要在输入值上执行的函数,所以天真地我会在接口中添加以下方法:

IInterface<TIn, TOut> DoSomethingWithFunc(Func<TIn, TOut> func);

哪个......不起作用。 TIn现在必须是协变的,TOut逆变。

我理解,我不能使用协变泛型类型作为方法的输入,但我想我可以在嵌套泛型类型中使用它们,它本身指定方差(Func<in T1, out TResult>)。

我尝试使用co / contravariant类型创建一个新的委托类型,并更改接口以接受此类型的参数,但无效(相同的错误)。

public delegate TOut F<in TDlgIn, out TDlgOut>(TDlgIn input);

public interface IInterface<in TIn, out TOut> {
  IInterface<TIn, TOut> DoSomethingWithFunc(F<TIn, TOut> func);
}

我有办法让编译器开心吗? 这是否可能(例如使用其他嵌套类型或其他通用参数)?如果没有,为什么不呢?

3 个答案:

答案 0 :(得分:1)

这样做是不安全的,因为你可以用它来做:

public class Id<I, O> : IInterface<I, O>
{
    private Func<I, O> f;
    public Id(Func<I, O> f) { this.f = f; }
    public IInterface<I, O> DoSomething(I i) { this.f(i); return this; }
    public IInterface<I, O> DoSomethingWithFunc(Func<I, O> newF) {
        this.f = newF;
        return this;
    }
}

然后

Func<Animal, string> fa;
IInterface<object, string> oi = new Id<object, string>(_ => "");
Interface<Monkey, string> mi = oi;  //safe
IInterface<Monkey, string> mi2 = mi.DoSomethingWithFunc(fa);
oi.DoSomething("not an animal!");

此时您将string传递给Func<Animal, string>

答案 1 :(得分:0)

你试过这个吗?

delegate TOut F<out TDlgIn, in TDlgOut>(TDlgIn input)

当传递代表时,共同/反向差异需要反过来。我不知道它是否有帮助。不知道你可能想在这个方法中做些什么。

答案 2 :(得分:0)

Error   CS1961  Invalid variance: The type parameter 'TIn' must be covariantly valid on 'IInterface<TIn, TOut>.DoSomethingWithFunc(Func<TIn, TOut>)'. 'TIn' is contravariant.

你实际上想要做的是,你是否正在将共同变体TOut类型作为参数传递给&#39; DoSomethingWithFunc&#39;方法。这是不可能的,只有In类型只能作为参数传递,Out仅作为结果传递。在您的示例中,您将TOut作为参数(它将被传递给&#39; DoSomethingWithFunc&#39;因为TOut是您的Func的结果)。

网上有很多关于它的文章(共同生效有什么意义&#39;,但我认为最好的解释是:https://blogs.msdn.microsoft.com/ericlippert/2009/12/03/exact-rules-for-variance-validity/

这意味着您可以将Func作为界面中方法的结果。