11

假设我有一个界面,例如

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

TIn逆变的,并且TOut变的。

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

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

这……不起作用。TIn现在要求是协变和TOut逆变的。

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

我尝试使用协变/逆变类型创建一个新的委托类型,并将接口更改为接受这种类型的参数,但无济于事(同样的错误)。

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);
}

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

4

3 回答 3

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!");

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

于 2016-02-18T12:58:54.593 回答
0

你试过这个吗?

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

在传递代表时,协方差需要反过来。我不知道它是否有帮助。不知道您可能想在该方法中做什么。

于 2016-02-18T13:51:04.337 回答
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 类型作为参数传递给 'DoSomethingWithFunc' 方法。这是不可能的,Only In 类型只能作为参数传递,Out 只能作为结果传递。在您的示例中,您将 TOut 作为参数(它将传递给“DoSomethingWithFunc”,因为 TOut 是您的 Func 的结果)。

网上有很多关于它的文章(“协变有效”是什么意思,但我认为最好的解释是:https ://blogs.msdn.microsoft.com/ericlippert/2009/12 /03/exact-rules-for-variance-validity/

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

于 2016-02-18T15:49:48.113 回答