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>) を指定するネストされたジェネリック型で使用できると考えました。

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

コンパイラを満足させる方法はありますか? これは可能ですか (たとえば、他のネストされた型、または追加のジェネリック引数を使用)? そうでない場合、なぜですか?

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

この時点で、 astringから anに渡されFunc<Animal, string>ます。

于 2016-02-18T12:58:54.593 に答える
0
Error   CS1961  Invalid variance: The type parameter 'TIn' must be covariantly valid on 'IInterface<TIn, TOut>.DoSomethingWithFunc(Func<TIn, TOut>)'. 'TIn' is contravariant.

あなたが実際にやろうとしていることは、「DoSomethingWithFunc」メソッドへの引数として共変の TOut 型を渡していることです。それは不可能です。In 型は引数としてのみ、Out は結果としてのみ渡すことができます。あなたの例では、TOut を引数として入れます (TOut は Func の結果であるため、「DoSomethingWithFunc」に渡されます)。

それに関する多くの記事がウェブ上にあります (「共変的に有効」とはどういう意味ですか? /03/分散妥当性のための正確な規則/

これは、もちろん、メソッドの結果として Func をインターフェイスに配置できることを意味します。

于 2016-02-18T15:49:48.113 に答える