我希望在程序启动时自动实例化一个Singleton。
“自动实例化”的意思是,Singleton中的代码应该在程序启动时实例化,而不需要其他代码的任何调用或声明。
所以我希望在程序启动时实例化并写出“MySingleton Instantiated”,而不是主代码做任何事情......
static class MySingleton
{
private static MySingleton self = new MySingleton();
protected MySingleton()
{
System.Console.WriteLine("MySingleton Instantiated");
}
}
除了这不起作用,因为C#只会在需要时初始化类的静态成员,即当它们被访问/等时。
那我该怎么办?可以这样做吗?
我没有亲自使用C ++(暂时没有使用C ++),但我很确定它可以在C ++中完成但不确定C#。
感谢任何帮助。感谢。
我真正想要做的是...... 将会有许多这些单例类(随着时间的推移可以添加更多),所有这些类都将继承自公共(抽象)父类(也称为PClass)。
PClass将有一个静态成员,它是PClasses的集合......以及一个将自己添加到集合中的构造函数......
然后理论上所有单例都会自动添加到集合中(因为当它们被实例化时,调用基类PClass构造函数并将新对象添加到集合中)...然后可以在不知道任何有关的情况下使用集合已经实现了什么子(单例)类,并且可以随时添加新的子(单例)类,而无需更改任何其他代码。
不幸的是,我无法让孩子们(单身人士)自我实例化......搞砸了我的小计划,导致了这篇文章。
希望我解释得那么好。
PS。是的,我意识到单身人士和他们的使用有不好的感觉......但有时他们很有用,即使撒旦自己做了单身人士,我仍然想知道我的问题是否能在C#中实现。非常感谢大家。
答案 0 :(得分:6)
Chris提到的IoC方法可能是最好的,但是我没能想到的“最佳”解决方案是用反射和属性来做一些时髦的事情:
public class InitOnLoad : Attribute
{
public static void Initialise()
{
// get a list of types which are marked with the InitOnLoad attribute
var types =
from t in AppDomain.CurrentDomain.GetAssemblies().SelectMany(a => a.GetTypes())
where t.GetCustomAttributes(typeof(InitOnLoad), false).Count() > 0
select t;
// process each type to force initialise it
foreach (var type in types)
{
// try to find a static field which is of the same type as the declaring class
var field = type.GetFields(System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic).Where(f => f.FieldType == type).FirstOrDefault();
// evaluate the static field if found
if (field != null) field.GetValue(null);
}
}
}
[InitOnLoad]
public class Foo
{
public static Foo x = new Foo();
private Foo()
{
Console.WriteLine("Foo is automatically initialised");
}
}
public class Bar
{
public static Bar x = new Bar();
private Bar()
{
Console.WriteLine("Bar is only initialised as required");
}
}
调用InitOnLoad.Initialise()添加到主方法。
您可以取消该属性,但这可能会导致不必要的类型被初始化并且不必要地占用内存(例如上面代码中的Bar)。
值得注意的是,这不会处理动态加载的任何程序集中包含的类型,除非您再次调用Initialise,而是基于您的问题(“在程序启动时自动实例化”)对你来说就是一个问题。
答案 1 :(得分:5)
虽然.NET模块理论上可以(IIRC)对模块负载等作出反应,但这不能通过C#获得。在某些框架(如ASP.NET)中,您可以通过配置使用钩子,例如通过处理程序或通过global.asax.cs进行黑客攻击 - 但是,对于常规C#应用程序(控制台,winform等),您必须手动触发它。例如,将调用承载您的Main
入口点的类上的静态构造函数。
那么:这里的用例是什么?什么时候延迟加载方法不行?
答案 2 :(得分:4)
根据你要做的事情,我会放弃真正的Singleton的想法,而是使用IoC库。
查看StructureMap,Castle Windsor,Ninject和/或Autofac。
这将允许您通过IoC库创建作为单例的类,具有您想要的任意数量,但它只是一个普通的旧类。
单身者有一个问题,他们真的搞乱了你的应用程序的可测试性(通过单元测试)。
只需对“Singleton Considered Harmful”进行谷歌搜索,您就会看到更多参考文献。
或者,您也可以使用简单的类工厂/方法工厂模式。
答案 3 :(得分:2)
我怀疑如果没有Main
做任何事情,这是可能的。如果不使用它,即使向类中添加static MySingleton() {}
也不能保证其实例化。
答案 4 :(得分:1)
你基本上要求.NET框架在加载程序集时调用某个函数。该功能将是PClass实例注册商。
C#中没有DllMain
。您可以通过在main方法中使用程序集级属性和一些代码来模拟这一点,该方法会在程序集加载时进行侦听。该属性可以指定一个“DllMain
”入口点,或指向您的PCIass继承类。
答案 5 :(得分:1)
切向,请允许我指出这不是真正实现的单例模式。这是C#中的常规(简化)实现(为简洁起见,不包括线程安全等内容):
public sealed class Singleton
{
static readonly Singleton _instance = new Singleton();
// private ctor
Singleton() {}
public static Singleton Instance
{
get { return _instance; }
}
}
您的代码中的这一行甚至不应该编译!
protected MySingleton()
说了这么多,我同意那个询问你的用例的人。知道这很好。 =)
答案 6 :(得分:0)
我不相信.Net框架中你想要的东西是可能的。基本上,您需要像运行时一样通知类型或调用某些预定义的静态方法,以便应用程序加载并运行或提供类似的机制。考虑一下开销。运行时唯一确保的是自动调用程序的主入口方法。而已。在那里你可以设置并初始化它们,但它没有任何自动。你仍然明确地挂钩并进行方法调用。
答案 7 :(得分:0)
“PClass将有一个静态成员,它是PClasses的集合......”
听起来像是可以通过Reflection轻松完成的事情。您不需要在启动时运行的代码;您可以随时根据需要构建这些类的列表。
这是一个在第一次读取Instances属性时将加载列表的示例,将查看当时加载的所有程序集(如果您只想查看与PClass相同的程序集,可以简化一下,但你的问题没有指明你想要查看的程序集,并且会将任何PClass后代的单个实例(但不是PClass本身)添加到列表中。每个PClass后代都需要一个无参数构造函数,但您不需要任何类构造函数。
public class PClass
{
private static List<PClass> m_instances;
public static IList<PClass> Instances
{
get
{
if (m_instances == null)
m_instances = LoadInstanceList();
return m_instances;
}
}
private static List<PClass> LoadInstanceList()
{
foreach (var assembly in AppDomain.GetAssemblies())
{
foreach (var type in assembly.GetTypes())
{
if (type.IsAssignableTo(typeof(PClass)) && type != typeof(PClass))
m_instances.Add(Activator.CreateInstance(type));
}
}
}
}