我确实有一个类,定义为:
public abstract class Singleton <T> : BaseObject
where T : Singleton <T>
{
}
我想在其他地方定义这些通用单例的数组。就像是
public MonoSingleton[] singletons;
如何检索该泛型的正确类型(如您所见,这似乎是递归的)?我怎样才能把这个写出来?
您是否正在尝试像这样进行“奇怪的递归模板模式”?
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
使用设计时代码,您将能够通过使用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在一些评论中说:
如果我确实使用:公共
Singleton<BaseObject>[]
单例;它会警告我:“错误 CS0309:BaseObject 类型必须可转换为单例”,以便将其用作泛型类型或方法“单例”中的参数“T”
这是另一个问题:你不能在类中做协方差。为了做这样的事情,你需要一个这样的界面:
public interface ISingleton<out TBaseObject> where TBaseObject : .........
并让Singleton<T>
类实现它。
因此,您可以通过以下方式创建这样的数组:
public ISingleton<BaseObject>[] singletons;
协方差允许您向上转换泛型参数,并且仅限于接口和委托。
在此处了解更多信息: