4

私は C++ テンプレート プログラミングから来ており、ジェネリックと非常に混同されることがあります。メソッド特化はないので、キャストでやってみました。ここに私が持っているものがあります:

public interface INonGen
{
    void Get<T>(ref T value);
}

public interface IGen<U> : INonGen
{

}

public class Gen<U> : IGen<U>
{
    private U u;
    public void Get<T>(ref T value)
    {
        if (value is U)
        {
            value = (T) u;
        }         
        else
            throw new Exception();
    }
}

これはコンパイルされません。

このキャストを作る方法はありますか?

これが必要な理由: C++ テンプレートでは、サポートされている型の特殊化と、例外をスローする特殊化されていないバージョンを作成します。

基本的な考え方は次のとおりです。ジェネリック メソッドを持つ非ジェネリック インターフェイス。正しい型を使用して値を取得しようとすると機能するはずですが、間違った型を使用しようとするとスローされる可能性があります。

タイプ セーフを維持する必要があるため、正しいタイプのインスタンス/値を返す必要があります。object に対するショートカットは受け入れられません。また、非ジェネリック インターフェイスで型を制約することもありません。

重複を避けるために、一般的な実装が行われます。複数の異なる型をサポートしたい (ただし、型の小さなセットのみ) が、クラスをインスタンス化する (および T の意味を定義する) ときにこれを決定する必要があります。非ジェネリック インターフェイスで任意の T を使用したアクセスを許可したい。つまり、インターフェイスで型のセットを明示的に指定したくありません。

4

4 に答える 4

3

オブジェクトを別のオブジェクトにキャストするときに、コンパイラが変換を見つけられない場合、エラーが報告されます。2 つの型パラメーターは制約されていないため、唯一のオプションは、キャストが失敗したときにをスローする代わりに返されるas演算子を使用することです。使用するには、ジェネリック型をクラスに制約する必要もあります。InvalidCastExceptionnullas

public class Gen<U> : IGen<U>
{
    private U u;
    public void Get<T>(ref T value)
            where T : class
    {
        if (value is U)
        {
            value = u as T;
        }         
        else
            throw new Exception();
    }
}

制約を追加したくない場合は、次のようにキャストできますObject

value = (T)(object)u;

ただし、コードに論理エラーがあります。もしvalue is U、それを保証するものは何u is Tですか?例えば:

 var gen = new Gen<Base>();
 gen.Set(new DerivedA()); // sets u;
 var b = new DerivedB();
 gen.Get(ref b);

この場合ではありvalue is Baseませ u is DerivedB。キャストは実行時に失敗します。

アップデート

あなたのコメントのいくつかを読んだ後、これが私がこれをどのように設計したかです:

public interface INonGen
{
    object Value { get; }
}

public interface IGen<U> : INonGen
{
}

public class Gen<U> : IGen<U>
{
    private U u;
    public object Value
    {
       get { return u; }
    }
}

そして、ディクショナリから項目を引き出すとき:

double value = (double)dictionary[key].Value;

InvalidCastExceptionランタイム変換がない場合は、がスローされます。簡単ですよね?

于 2013-10-17T11:19:01.123 に答える
1

INonGen特にジェネリックメソッドがあるため、このコンテキストでの目的がわかりません。それを取り除けば、あなたはこれを行うことができます。どちらがコンパイルされますか-チェックしました;o)

public interface IGen<T>
{
    void Get(ref T value);
}

public class Gen<T, U> : IGen<T> where U : T
{
    private U u;

    public void Get(ref T value) 
    {
        if (value is U)
        {
            value = (T)u;
        }
        else
            throw new Exception();
    }
}

U : Tポイントは、実装クラスで制約を指定できないため、インターフェイス メソッドだけでジェネリック型引数を持つことはできないということです 。インターフェイス定義自体にある必要があります。Uまた、実装クラスは、ジェネリック型引数との両方について明示的に認識している必要がありTます。これにより、コンパイラはキャスト操作を検証できます。

using のルートをたどることもできますが、これは型安全ではないため、コンパイラに頼るのではなくas、結果が の場合を処理する必要があります。null推奨されません。

実際の例で、INonGen他の非ジェネリック メソッド、または実装クラスが実装メソッドの外部でメソッドのジェネリック型引数について知る必要がないジェネリック メソッドがある場合は、問題なく元に戻すことができます。

public interface INonGen
{
    void NonGenericMethod();
    void GenericMethod<V>(V parameter);
}

public interface IGen<T> : INonGen
{
    void Get(ref T value);
}

public class Gen<T, U> : IGen<T> where U : T
{
    private U u;

    public void Get(ref T value) 
    {
        if (value is U)
        {
            value = (T)u;
        }
        else
            throw new Exception();
    }

    public void NonGenericMethod()
    {
    }

    public void GenericMethod<V>(V parameter)
    {
    }
}
于 2013-10-17T11:40:19.257 に答える
0

まず、これにも使用しないでくださいref。それからあなたの問題は無意味になります。

public interface IThing
{
    object Value { get; }
}

public interface IThing<T> : IThing
{
    T Value { get; }
}

public class Thing<T> : IThing<T>
{
    private T t;

    public object Value
    {
        get
        {
            return this.Get();
        }
    }

    public T Value<T>()
    {
        get
        {
            return this.t;
        }
    }
}

あなたが本当にジェネリックな他のものを受け入れたいのなら、それは正しい型に制約されています

public interface ICrazyThing<T>
{
    void Get<T>(ref T crazy);
}

public class CrazyThing<U, T> : IThing<T> where T : U
{
    private U u;

    public void Get<T>(ref T crazy)
    {
       crazy = this.u;   
    }
}

クレイジーな世界でも、渡された値は結果に関係のない無意味なインスタンス化であるため、outよりも良い選択です。ref

于 2013-10-17T11:25:55.710 に答える