0

次のように定義されているクラスがあります。

public abstract class Singleton <T> : BaseObject
    where T : Singleton <T>
{
}

これらの汎用シングルトンの配列を別の場所で定義したいと考えています。何かのようなもの

public MonoSingleton[] singletons;

そのジェネリックの適切なタイプを取得するにはどうすればよいですか (ご覧のとおり、再帰的であるように見えます)。これを書き出すにはどうすればよいですか?

4

2 に答える 2

1

このように、「妙に再帰的なテンプレート パターン」を実行しようとしていますか?

class CuriouslyRecursiveBase<T>
{

}

class CuriouslyRecursiveDervied<T> : CuriouslyRecursiveBase<T>
{

}

class MyClass : CuriouslyRecursiveBase<MyClass>
{

}

ベースから派生したものをインスタンス化するには、次を使用します。

class CuriouslyRecursiveBase<T>
{
    public static void InstantiateDerived()
    {
        T instance = (T)Activator.CreateInstance(typeof(T));
    }
}

T は実際には派生型 ( MyClass) であり、不思議なことに型 ( CuriouslyRecursive<MyClass>) でもあるためです。

あなたの問題に具体的に適用されます:

// Create a common interface that all singletons use. This allows 
// us to add them all to a list.
interface ISingleton { }

class Singleton<T> : ISingleton
{
    // Store our list of ISingletons
    static List<ISingleton> instances = new List<ISingleton>();
    static T instance;

    protected Singleton() { }

    public static T GetInstance()
    {
        // Either return the existing instnace, or create a new one
        if (Singleton<T>.instance == null)
        {
            Singleton<T>.instance = (T)Activator.CreateInstance(typeof(T));

            // Use a common interface so they can all be stored together.
            // Avoids the previously mentioned co-variance problem.
            // Also, compiler isn't built to follow curious recursiveness,
            // so use a dynamic statement to force runtime re-evaluation of 
            // the type hierarchy. Try to avoid dynamic statements in general
            // but in this case its useful.
            instances.Add((dynamic)Singleton<T>.instance);
        }

        return Singleton<T>.instance;
    }
}

class MyClass : Singleton<MyClass>
{

}

public static void Main()
{
    MyClass my = MyClass.GetInstance();
}

より詳しい情報:

http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern

于 2013-02-07T16:21:56.593 に答える
1

typeof設計時のコードを使用すると、演算子を使用し、ジェネリック パラメーターに何らかの引数を与えることで、型を取得できます。

typeof(Singleton<SomeImplementationOfBaseObject>)

または

typeof(Singleton<>)

しかし、別の方法があります: リフレクションです。

Type singletonType = Type.GetType("NamespaceA.NamespaceN.Singleton`1");

1 の部分は、ジェネリック パラメーターの数です。あなたがそれのようなものを持っているなら、Class<T, S>それは 2 などです。

リフレクションを使用すると、ジェネリック引数を指定する必要がないことに注意してください。とにかく、ジェネリック パラメーターを使用して型を取得できます。一般的な引数を指定するには、次のようにします。

Type genericType = singletonType.MakeGenericType(typeof(SomeImplementationOfBaseObject));

または、直接取得したい場合は、次のようにします。

Type singletonType = Type.GetType("NamespaceA.NamespaceN.Singleton`1[[NamespaceA.NamespaceN.SomeImplementationOfBaseObject]]");

[[ ]]ジェネリック引数として渡された型のフル ネーム内の文字列。ジェネリック型が実行中のアセンブリと同じでない場合は、アセンブリ修飾名を指定する必要があることに注意してください (たとえば、 "NamespaceA.MyClass, MyAssembly" )。

アップデート

OPはコメントで次のように述べています。

public Singleton<BaseObject>[]singletons; を使用すると、ジェネリック型またはメソッド「Singleton」でパラメーター「T」として使用するために、「エラー CS0309: The type BaseObject' must be convertible to Singleton」という警告が表示されます。

これは別の問題です。クラスで共分散を行うことはできません。そのようなことを行うには、次のようなインターフェースが必要です。

public interface ISingleton<out TBaseObject> where TBaseObject : .........

そして、Singleton<T>クラスにそれを実装させます。

したがって、このような配列を次のように作成できます。

public ISingleton<BaseObject>[] singletons;

Covarianceを使用すると、ジェネリック パラメーターをアップキャストできます。これは、インターフェイスとデリゲートに限定されます。

詳細はこちら:

于 2013-02-07T16:22:29.450 に答える