2016-04-01 13 views
2

:CLRは、それがどの表現の変更を加える必要がないことを保証することができたときに基本的には、分散が適用さ値型に共分散を使用する方法は?あなたは、値型のための共分散を使用することはできません

Func<string> refTypeFunc =() => "foo"; 
Func<int> valueTypeFunc =() => 123; 

Func<object> a = refTypeFunc; // works 
Func<object> b = valueTypeFunc; // doesn't work 

This answer by Jon Skeetは理由を説明します値に。参照はすべて同じように見えるので、IEnumerable<string>IEnumerable<object>として使用することができます。ネイティブコード自体は、インフラストラクチャが確実に有効であることを保証している限り、値を使って何をやっているのかを知る必要はありません。

IEnumerable<int>IEnumerable<object>として処理する値型の場合、シーケンスを使用するコードはボクシング変換を実行するかどうかを判断する必要があります。

少なくともFuncのためにあなたがこれを行うことができます。

Func<object> c =() => valueTypeFunc(); 

しかし、出て、このような簡単な方法は、ほとんどの場合に使用することはできません。私はICovariant<T>を持っている場合今、私はICovariant<object>にキャストすることはできません、と私はそれのうち簡単な方法を見ていない

interface ICovariant<out T> 
{ 
    Func<T> InnerFunc { get; } 
} 

:私のように定義されたインタフェースを持っていると言います。私が知っているTobjectであることができます - すべてできます。この場合、私は何ができますか?簡単な回避策がない場合は、他に最善の方法はありますか?

+0

デザインは基本的に破っているobject' 'への一般的な値をキャストするためにあなたを必要とする理由たぶん自問してみてください第一にジェネリック医薬品の全目的。 – juharr

+0

@juharrジェネリックの使用時には、実装と使用の両方がはるかにクリーンです。 'T'を返すメソッドがあります - ' object'を返すことは、呼び出しコードに醜いダウンキャスティングをたくさん追加します。 'T'を' object'として使うことは多相に非常に役立ちます。例えば、多くのオブジェクトインスタンスをリストに追加することです。 –

+0

表現の変更がないようにしたい場合は、 'where T:class'をそこに貼り付けてください。 –

答えて

2

変換を行うためには、共変インターフェイスの特別な実装を行う必要があります。このような何か:

public class Boxer<T, U> : ICovariant<T> where U : struct, T 
{ 
    public Boxer(ICovariant<U> foo) 
    { 
     mFoo = foo; 
    } 

    public Func<T> CallMe =>() => mFoo.CallMe(); 

    private readonly ICovariant<U> mFoo; 
} 

これは、今、あなたはICovariant<T>インタフェースの値型の実装をラップすることができます。あなたが入力する不快なすべての一般的なパラメータを見つけた場合、あなたはあなたのための控除を行うための静的メソッドを作成することができます。

static void BoxIt<T, U>(IFoo<U> fooU, out IFoo<T> fooT) where U : struct, T 
{ 
    fooT = new Boxer<T, U>(fooU); 
} 
関連する問題