4

私はキャッチ22に陥り、抜け道が見つからないようです。以下のサンプル コードの GetInstance メソッドで表される単純な [Service Locator][1] を実装しようとしています。ここでの問題は、return ステートメントで次のようなコンパイラ エラーが発生することです。

Cannot implicitly convert type 'Cyberspace.SubClass' to 'Cyberspace.BaseClass<T>'

SubClass 自体がジェネリック クラスになるように書き直そうとしましたが、DoSomething メソッドの return ステートメントでコンパイラ エラーが発生します。

GetInstace メソッドで抽象的な戻り値の型を持つことを可能にする Service Locator パターンの原則を保持したまま、このコードをコンパイルできる人はいますか? それとも、ここで不可能なことを達成しようとしていますか?

namespace Cyberspace
{
    class BaseClass<T>
    {
        BaseClass<T> GetInstance() 
        { 
            return new SubClass();
        }
        virtual T DoSomething() { return default(T); }          
    }

    class SubClass : BaseClass<OtherClass>
    {
        public override OtherClass DoSomething()
        { 
            var other = new OtherClass { Description = "Generics are hard"};
            return other;
        }
    }

    class OtherClass
    {
        internal string Description { get; set; }
    }
}

試行 2:

namespace Cyberspace
{
    class BaseClass<T>
    {
        static BaseClass<T> GetInstance() // The "Service Locator" method
        { 
            return new SubClass<T>(); 
        }
        internal virtual T DoSomething() { return default(T); }        
    }

    class SubClass<T> : BaseClass<T> where T: OtherClass
    {
        internal override T DoSomething()
        { 
            var other = new OtherClass { Description = "Generics are hard"};
            return (T) other;
        }
    }

    class OtherClass
    {
        internal string Description { get; set; }
    }
}

これにより、オンラインで次のエラーが発生しますreturn new SubClass<T>();

The type 'T' cannot be used as type parameter 'T' in the generic type or method 'Cyberspace.SubClass<T>'. There is no boxing conversion or type parameter conversion from 'T' to 'Cyberspace.OtherClass'

4

2 に答える 2

3

あなたが実際に何をしようとしているのかはわかりませんが、コンパイル エラーが発生する理由はわかります。

このメソッドから返されるもの:

BaseClass<T> GetInstance()

任意の型を処理できる必要Tがあります (型の制約がないため)。SubClassすべてのタイプではなく、1 つのタイプのみを処理できます。したがって、返品することはできません。

于 2012-06-28T13:41:20.573 に答える
1

型パラメーターを使用する場合は、Tのように宣言します。しかし、あなたの場合、特定のタイプが必要なようです。ジェネリックは必要ありません。T

class SubClass : BaseClass<OtherClass>
{
    internal override OtherClass DoSomething()
    { 
        var other = new OtherClass { Description = "Generics are hard"};
        return other;
    }
}

以下が機能しないのはなぜですか?

        var other = new OtherClass { Description = "Generics are hard"};
        return (T) other;

Tから派生する可能性があるためOtherClassです。OtherClassから派生したクラスに変換することはできませんOtherClass。意味がなく、コンパイラはそれをキャッチするのに十分スマートです。


コメントでの議論は、次の回避策につながります。

return (BaseClass<T>)(object)new SubClass();

もちろん、これは実行時に型が揃っている場合にのみ機能します。

于 2012-06-28T14:01:50.953 に答える