2014-12-12 2 views
1

Я пытался реализовать одноэлементное наследование для моей системы журналов, поэтому я мог бы отделить системные события от поведения пользователя. Я нашел this nice post in Java. Несмотря на разницу Generics, я мог бы реализовать эту прикрепленную первую версию (ненавязчивость на некоторое время).Singleton Inheritance C#

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# он может быть другим.

+0

У одиночек есть частные конструкторы, поэтому вы не сможете использовать invoke. – tdbeckett

+0

Вы не можете вызвать абстрактный класс. Сделать это Singleton не делает с тех пор. – tdbeckett

+0

Невозможно обеспечить соблюдение требования Singleton для классов детей. – tdbeckett

ответ

0

Если вы укажете, что общий тип должен будет наследовать от журнала и что он будет иметь новый(), вы можете избежать использования конструктора без параметров. Вы также должны изменить свой конструктор защищенные таким образом, чтобы ребенок класс можно назвать:

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() { } 
} 

Я не думаю, что вы можете назвать частные конструкторы вне класса (они являются частными, в конце концов), но через отражение может быть что-то, что можно сделать (я не эксперт по размышлениям). Использование защищенных, а не частных может получить нужные вам результаты.

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; } } 
    } 
} 

Т.е. просто следуйте нормальному одиночному идиому для каждого из реальных одноэлементных классов.

+0

Спасибо, Питер! И как я могу хранить эти слова в словаре? – user2203748

+0

Зачем ты хочешь? В каком контексте у вас есть «Тип», который вы можете использовать для ключа в словаре, но не сможете просто написать что-то вроде «UserLog.Instance» или «SystemLog.Instance», если это необходимо? То есть как получилось, что вы получили экземпляр типа «SingleTone» одного объекта, не зная ни фактического имени типа, ни уже имеющего экземпляр singleton? –