Как create.NET интерфейс со статическими членами?

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

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

конечно, это не работает, но это то, что я хотел бы. Есть предложения?

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

8 ответов


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


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

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

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


хорошо, я сделал этот ответ Wiki, потому что я просто собираюсь предложить мнение, которое находится по касательной к вашему вопросу.

Я лично думаю, что синглтоны waaay чрезмерно используются, его вариант использования, что IMO на самом деле достаточно редко, в большинстве случаев статический класс подходит для случая использования намного лучше, а в других случаях просто созданный фабрикой имитируемый объект является лучшим выбором, фактический синглтон намного реже, чем думают люди.

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


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

вместо этого напишите модульный тест.


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


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

вы можете попробовать с интерфейсом фабричного стиля

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

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


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

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

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

строковый ключ { get; } объект SettingValue { get; set; } Область SettingScope { get; set; } }

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

}