4

Javaの世界から来て、ジェネリックスとC#を使ったプログラミングはしばしば頭痛の種です。このように:

interface ISomeObject { }
class SomeObjectA : ISomeObject { }
class SomeObjectB : ISomeObject { }


interface ISomething<T> where T : ISomeObject
{
    T GetObject();
}
class SomethingA : ISomething<SomeObjectA>
{
    public SomeObjectA GetObject() { return new SomeObjectA(); }
}
class SomethingB : ISomething<SomeObjectB>
{
    public SomeObjectB GetObject() { return new SomeObjectB(); }
}


class SomeContainer
{

    private ISomething<ISomeObject> Something;

    public void SetSomething<T>(ISomething<T> s) where T : ISomeObject
    {
        Something = (ISomething<ISomeObject>)s;
    }
}


class TestContainerSomething
{
    static public void Test()
    {
        SomeContainer Container = new SomeContainer();
        Container.SetSomething<SomeObjectA>(new SomethingA());
    }
}

その結果、InvalidCastExceptionatになりSomething = (ISomething<ISomeObject>)s;ます。Javaでは、これは機能し、ジェネリックワイルドカードを使用することもできます(他のすべてが失敗した場合)<?>。これはC#では不可能です。

これは問題を説明するためにまとめた単なる例ですが、この例外をどのように排除できますか?唯一の主な制約は、ジェネリッククラスになるSomeContainer ことはできないということです

****:これについては多くの質問がありますが、(私が見つけた)それらのどれも非ジェネリッククラス内のジェネリッククラスメンバーに対応していません。

**更新**

メソッド内に、SetSomething次の行を追加しました。

Console.WriteLine(s.GetType().IsSubclassOf(typeof(ISomething<SomeObjectA>)));
Console.WriteLine(s.GetType().ToString() + " : " + s.GetType().BaseType.ToString());
foreach (var i in s.GetType().GetInterfaces())
{
    Console.WriteLine(i.ToString());
}

驚いたことに、これは

False
SomeThingA : System.Object
ISomething`1[SomeObjectA]

これが、この例外が発生する理由ですか?

4

2 に答える 2

5

ISomethingTを返すメソッドしかない場合は、 Outキーワードが修正されます

interface ISomething<out T> where T : ISomeObject

ジェネリックインターフェイスを作成するときに、型引数が異なるインターフェイスインスタンス間で暗黙的な変換を行うかどうかを指定できます。

それは共変性と反変性と呼ばれます

Eric Lippertには、これについて考える必要がある理由に関する一連の優れた記事があります。ここでは、インターフェイスの分散が使用されています

これが私のコードです。これは私にとって期待どおりに機能します

interface ISomeObject { }
class SomeObjectA : ISomeObject { }
class SomeObjectB : ISomeObject { }


interface ISomething<out T> where T : ISomeObject
{
    T GetObject();
}
class SomethingA : ISomething<SomeObjectA>
{
    public SomeObjectA GetObject() { return new SomeObjectA(); }
}
class SomethingB : ISomething<SomeObjectB>
{
    public SomeObjectB GetObject() { return new SomeObjectB(); }
}


class SomeContainer
{

    private ISomething<ISomeObject> Something;

    public void SetSomething<T>(ISomething<T> s) where T : ISomeObject
    {
        Something = (ISomething<ISomeObject>)s;
    }
}


class TestContainerSomething
{
    static public void Test()
    {
        SomeContainer Container = new SomeContainer();
        Container.SetSomething<SomeObjectA>(new SomethingA());
    }
}
于 2012-11-29T15:35:18.533 に答える
2

ジェネリック インターフェイスに非ジェネリック インターフェイスを実装させて、欠落を回避すると便利な場合があります。<?>

interface ISomething
{
    object GetObject();
}

interface ISomething<T> : ISomething
    where T : ISomeObject
{
    T GetObject();
}

public class SomeImplementation<T> : ISomething<T>
{
    public T GetObject()
    {
        ...
    }

    object ISomething.GetObject()
    {
        return this.GetObject(); // Calls non generic version
    }
}

コレクションは、非ジェネリック インターフェイスを使用して型指定できます。

var list = new List<ISomething>();
list.Add(new SomeImplementation<string>());
list.Add(new SomeImplementation<int>());
于 2012-11-29T15:47:36.143 に答える