代码之家  ›  专栏  ›  技术社区  ›  devlop

如何:在C中自动实例化singleton#

  •  6
  • devlop  · 技术社区  · 15 年前

    我想要一个在程序启动时自动实例化的单例。

    我所说的“自动实例化”是指,单例中的代码应该在程序启动时实例化自己,而不需要其他代码进行任何调用或声明。

    所以我想在程序启动时(不需要主代码做任何事情)实例化并写出“mysingleton installed”…

    static class MySingleton
    {
        private static MySingleton self = new MySingleton();
    
        protected MySingleton()
        {
            System.Console.WriteLine("MySingleton Instantiated");
        }
    }
    

    但这不起作用,因为C只在需要时初始化类的静态成员,即当它们被访问时/etc。

    那我该怎么办?能做到吗?

    我还没有亲自做过C++(一段时间没有使用C++),但我确信它可以在C++中完成,但不能肯定C++。

    感谢您的帮助。谢谢。


    我真正想做的是… 会有许多这样的单例类(并且随着时间的推移可以添加更多的类),所有这些类都将从一个公共(抽象)父类(aka)继承。PClass)

    pclass将具有一个静态成员,该静态成员是pclass的集合…以及一个将自己添加到集合中的构造函数…

    然后理论上,所有的单例都将自动添加到集合中(因为当它们被实例化时,将调用基PClass构造函数并将新对象添加到集合中)。然后可以在不知道实现了什么子类(singleton)的情况下使用集合,并且可以随时添加新的子类(singleton)而不必更改任何其他代码。

    不幸的是,我不能让孩子们(独生子)来例示自己…把我的小计划搞砸了,结果写了这篇文章。

    希望我解释得足够好。


    是的,我意识到单身汉和他们的使用都有不好的感觉…但有时它们是有用的,即使撒旦自己制造了单重子,我还是想知道我的问题是否可以在C中实现。谢谢大家。

    8 回复  |  直到 15 年前
        1
  •  6
  •   Richard    15 年前

    克里斯提到的国际奥委会方法可能是最好的,但如果不能做到这一点,我能想到的“最佳”解决方案就是做一些有反射力和属性的事情:

    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)。

    值得注意的是,这不会处理动态加载的任何程序集中包含的类型,除非您再次调用初始化,但基于您的问题(“在程序启动时自动实例化”),这听起来不像是问题。

        2
  •  5
  •   Marc Gravell    15 年前

    虽然.NET模块理论上可以(IIRC)对模块加载等作出反应,但这并不是通过C_实现的。在某些框架(如ASP.NET)中,您可以通过配置使用钩子,例如通过处理程序或global.asax.cs对其进行黑客攻击,但是对于常规的C应用程序(控制台、WinForm等),您必须手动触发它。例如,类上承载 Main 入口点将被调用。

    那么:这里的用例是什么?什么时候懒惰的加载方法不好?

        3
  •  4
  •   Chris Brandsma    15 年前

    基于你想做的,我放弃了真正单身的想法,转而使用IOC图书馆。

    查看结构图、城堡温莎、Ninject和/或Autopac。

    这将允许您通过IOC库创建一个单独的类,可以拥有任意多的类,但它只是一个普通的旧类。

    单例存在一个问题,那就是它们确实会破坏应用程序的可测试性(通过单元测试)。

    只需在谷歌搜索“被认为有害的单身汉”,你就会看到更多的参考资料。

    或者,也可以使用简单的类工厂/方法工厂模式。

        4
  •  2
  •   Mehrdad Afshari    15 年前

    我怀疑这不可能从 Main . 甚至添加 static MySingleton() {} 如果不使用类,则不保证它的实例化。

        5
  •  1
  •   tofi9    15 年前

    您基本上要求.NET框架在加载程序集时调用某个函数。该函数将是pclass实例注册器。

    没有 DllMain 在C语言中。您可以通过在主方法中拥有一个程序集级属性和一些代码来模拟这一点,主方法在加载程序集时监听这些代码。属性可以有一个“ 德尔曼 “指定的入口点或指向PCIASS继承的类。

        6
  •  1
  •   Garrett    15 年前

    切切地说,让我指出这并不是通常实现的单例模式。下面是C中的常规(简化)实现(不包括线程安全等内容,以实现简洁性):

    public sealed class Singleton
    {
    static readonly Singleton _instance = new Singleton();
    
    // private ctor
    Singleton() {}
    
     public static Singleton Instance
     {
      get { return _instance; }
     }
    }
    

    您的代码中的这一行甚至不应该编译!

    protected MySingleton()
    

    说了这么多,我同意那个询问你的用例的人。那就好了。=)

        7
  •  0
  •   Mehmet Aras    15 年前

    我不相信你想要的在.NET框架中是可能的。基本上,您希望类似于运行时的东西通知类型,或者对类型调用一些预定义的静态方法,以通知应用程序已加载并正在运行,或者提供类似的机制。考虑一下开销。运行时唯一确保的是自动调用程序的主入口方法。就是这样。在那里,您可以设置和初始化事物,但没有自动的功能。您仍然显式地挂接事情和进行方法调用。

        8
  •  0
  •   Joe White    15 年前

    “pclass将有一个静态成员,该成员是pclass的集合…”

    听起来像是可以通过反射轻松完成的事情。您不需要在启动时运行的代码;只要您需要,就可以构建这些类的列表。

    下面是一个示例,当您第一次读取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));
                }
            }
        }
    }