Подтвердить что ты не робот

Как создать интерфейс .NET со статическими элементами?

В .NET 3.5 я хотел бы создать одноэлементный интерфейс:

interface ISingleton <T>
{
  public static T Instance {get;}
}

Конечно, это не работает, но это то, что я хотел бы. Любые предложения?

EDIT: Я просто хочу, чтобы было известно, что все singeltons будут иметь статическое свойство Instance типа класса. Это всегда есть. Интерфейс был бы явным способом выразить это.

4b9b3361

Ответ 1

Интерфейс не может, насколько мне известно, быть Singleton, поскольку он фактически не существует. Интерфейс - это контракт, которым должна следовать реализация. Таким образом, реализация может быть одиночной, но интерфейс не может.

Ответ 2

В то время как я согласен с другими плакатами в том, что синглтоны очень много используются, возможным решением вашего вопроса является предоставление абстрактного базового класса с параметром типа производного singleton:

public abstract class Singleton<T> where T : Singleton<T>
{
  private static T _instance;

  public static T Instance
  {
    get { return _instance; }
    protected set { _instance = value; }
  }
}

Любой класс, полученный из Singleton, будет иметь свойство статического экземпляра правильного типа:

public class MySingleton : Singleton<MySingleton>
{
    static MySingleton()
    {
        Instance = new MySingleton();
    }

    private MySingleton() { } 
}

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

Ответ 3

Хорошо, я сделал этот ответ Вики, потому что я просто собираюсь предложить мнение, касающееся вашего вопроса.

Я лично считаю, что синглтоны с избытком используются, это пример использования, который ИМО на самом деле достаточно редок, в большинстве случаев статический класс намного лучше подходит для использования, а в других случаях только созданный объект imutable factory лучший выбор, реальный синглтон гораздо реже, чем думают люди.

У меня не было бы интерфейса для описания общего шаблона для этого, так как я действительно хотел бы, чтобы каждое использование одноэлементного представления было очень тщательно и обосновано.

Ответ 4

Я просто хочу, чтобы было известно, что все singeltons будут иметь статическое свойство Instance типа класса. Это всегда есть. Интерфейс был бы явным способом выразить это.

Вместо этого напишите unit test.

Ответ 5

Я знаю, что это не ваш вопрос, но сколько у вас синглов у вас такое, что вам нужен интерфейс? Это пахнет плохим дизайном для меня - можете ли вы объяснить, почему эти классы должны быть одиночными, а не экземплярами? Если ваш ответ - это память, я бы предложил вам переосмыслить ваше приложение, и если вы действительно обеспокоены, загляните в шаблон мухи (или, возможно, простой шаблон factory). Извините, что не ответил на вопрос напрямую, но это не похоже на отличную идею.

Ответ 6

Кроме того, как вы заявляете, он не работает, как вы используете этот интерфейс и класс реализации?

Вы можете попробовать с интерфейсом Factory -style

interface ISingletonFactory<T>
{
    public T Instance {get;}
}

public class SingletonFactory: ISingletonFactory<Singleton>
{
    public Singleton Instance {get { return Singleton.Instance;}}
}

public class Singleton
{
    private Singleton foo;
    public static Singleton Instance { get { return foo; } }
}

Ответ 7

Учитывая классическое понятие ООП интерфейса, которое определяет его как Контракт между реализующими классами, вы не можете добавить к нему такую ​​вещь, как статический метод. Если бы вы могли это сделать, вы бы закончили нечто более похожее на абстрактный класс, в котором у вас есть частичная реализация вашего класса и других частей, требуемых для расширяющих классов.

Ответ 8

Как указано, вы не можете этого сделать, и есть веские причины, почему вы не должны.

Метод, который я реализовал в прошлом, создает интерфейс и абстрактный базовый класс, который реализует интерфейс. Это выглядит примерно так:

public interface IMyCompanySetting
{
    XmlNode Serialize();
    IMyCompanySetting Deserialize(XmlNode pattern);
    string SettingName { get; }

string Ключ {get; }       object SettingValue {get; задавать; }       SettingScope Scope {get; задавать; }   }

public abstract class MyCompanySettingBase : IMyCompanySetting
{
    public MyCompanySettingBase() {}
    public MyCompanySettingBase(XmlNode pattern)
    {
        Deserialize(pattern);
    }
    #region IMyCompanySetting Members

    public abstract XmlNode Serialize();
    public abstract IMyCompanySetting Deserialize(XmlNode pattern);
    public abstract string SettingName{ get; }
public abstract string Key { get; }
    public abstract SettingScope Scope{ get; set; }
    public abstract object SettingValue{ get; set; }

    #endregion

public static XmlNode WrapInSettingEnvelope(XmlNode innerNode, IMyCompanySetting theSetting)
{
    // Write the top of the envelope.
    XmlTextWriter xtw = null;
    MemoryStream theStream = OpenSettingEnvelope(theSetting, ref xtw);

    // Insert the message.
    xtw.WriteNode(new XmlTextReader(innerNode.OuterXml, XmlNodeType.Element, null), true);

    // Close the envelope.
    XmlNode retNode = CloseSettingEnvelope(xtw, theStream);
    return retNode;

}

public static MemoryStream OpenSettingEnvelope(IMyCompanySetting theSetting, ref XmlTextWriter theWriter)
{
    MemoryStream theStream = new MemoryStream();
    theWriter = new XmlTextWriter(theStream, Encoding.ASCII);
    System.Type messageType = theSetting.GetType();

    string[] fullAssembly = messageType.Assembly.ToString().Split(',');
    string assemblyName = fullAssembly[0].Trim();

    theWriter.WriteStartElement(theSetting.SettingName);
    theWriter.WriteAttributeString("type", messageType.ToString());
    theWriter.WriteAttributeString("assembly", assemblyName);
    theWriter.WriteAttributeString("scope", ConfigurationManager.ScopeName(theSetting.Scope));

    return theStream;
}

public static XmlNode CloseSettingEnvelope(XmlTextWriter xtw, MemoryStream theStream)
{
    XmlDocument retDoc = new XmlDocument();
    try
    {
        // Close the envelope.
        xtw.WriteEndElement();
        xtw.Flush();

        // Return the node.
        string xmlString = Encoding.ASCII.GetString(theStream.ToArray());
        retDoc.LoadXml(xmlString);
    }
    catch (XmlException)
    {
        string xmlString = Encoding.ASCII.GetString(theStream.ToArray());
        Trace.WriteLine(xmlString);
        retDoc.LoadXml(@"<error/>");
    }
    catch (Exception)
    {
        retDoc.LoadXml(@"<error/>");
    }
    return retDoc.DocumentElement;
}

}