【问题标题】:Singleton Inheritance C#单例继承 C#
【发布时间】:2014-12-12 19:03:32
【问题描述】:

我试图为我的日志系统实现单例继承,这样我就能够将系统事件与用户行为分开。我找到了this nice post in Java。尽管存在泛型差异,但我可以实现这个附加的第一个版本(暂时非线程安全)。

public abstract class Log
{

    private static volatile Dictionary<Type, Log> instances = new Dictionary<Type, Log>();

    public static Log GetInstance(Type type) {

        Log instance = null;
        if (!Log.instances.ContainsKey(type))
        {
            ConstructorInfo ctor = type.GetConstructor(BindingFlags.Default,
                    null,
                    new Type[0],
                    new ParameterModifier[0]);

            instance = ctor.Invoke(new object[0]) as Log;
            instances.Add(type, instance);
        }
        else
        {
            instance = Log.instances[type];
        }

        return instance;
    }

    private Log() { }

    public class UserLog : Log
    {
        private UserLog() : base() { }
    }       

    public class SystemLog : Log
    {
        private SystemLog() : base() { }
    }

}

上面的高亮行显示了创建新实例的尝试。但是它不起作用并返回一个 ConstructorInfo 的空实例。

1) 关于如何使用 GetConstructor 方法的任何想法?我知道它有 3 个重载版本,但第一个仅适用于公共构造函数。如果我将构造函数的可见性更改为公共,我可以使用其他重载版本 (this one),但这个特定版本我什至不能使用公共构造函数。

2) 在 C# 中,是否可以像我尝试的那样从其他类调用私有构造函数?我已经用 Java 实现了它,但在 C# 中可能会有所不同。

【问题讨论】:

  • 单例有私有构造函数,所以你不能使用invoke。
  • 您不能调用抽象类。从那以后,让它成为一个单身人士就不行了。
  • 没有办法对子类强制执行 Singleton 要求。
  • 注意因为你的父类构造函数是私有的,你不能在子类中调用构造函数。 UserLog() : base() {} 将不起作用。

标签: c# design-patterns reflection singleton


【解决方案1】:

由于您的绑定标志未指定Private,因此您将无法获得私有构造函数。如果是公开的,则需要指定Public

也就是说,我不明白您希望以这种方式实现这一点。似乎无缘无故地做了很多额外的工作。

我会这样做:

public abstract class Log
{
    public class UserLog : Log
    {
        private static readonly Lazy<UserLog> _instance =
            new Lazy<UserLog>(() => new UserLog());
        public static UserLog Instance { get { return _instance.Value; } }
    }

    public class SystemLog : Log
    {
        private static readonly Lazy<SystemLog > _instance =
            new Lazy<SystemLog >(() => new SystemLog ());
        public static SystemLog Instance { get { return _instance.Value; } }
    }
}

即只需遵循每个实际单例类的正常单例习语即可。

【讨论】:

  • 谢谢彼得!我怎样才能将这些实例存储在字典中?
  • 为什么要这样做?在什么情况下,你有一个Type 可以用作字典中的键,但不能简单地写成UserLog.InstanceSystemLog.Instance 之类的东西? IE。在不知道实际类型名称或已经拥有单例实例的情况下,您如何获得了单例对象的 Type 实例?
【解决方案2】:

如果您指定泛型类型必须从 Log 继承,并且它将具有 new(),则可以使用无参数构造函数。您还必须将构造函数更改为受保护的,以便子类可以调用它:

public abstract class Log
{
    private static volatile Dictionary<Type, Log> instances = new Dictionary<Type, Log>();
    public static TLogType GetInstance<TLogType>() where TLogType : Log, new()
    {
        TLogType instance = null;
        var type = typeof(TLogType);
        if (!Log.instances.ContainsKey(type))
        {
            instance = new TLogType();
            instances.Add(type, instance);
        }
        else
        {
            instance = (TLogType)Log.instances[type];
        }

        return instance;
    }
    protected Log() { }
}

我认为你不能在类之外调用私有构造函数(毕竟它们是私有的),但是通过反射可能可以完成一些事情(我不是反射专家)。使用 protected 而不是 private 可能会得到你想要的结果。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多