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

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

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

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

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

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
12
0
13 506
9
Перейти к ответу Данный вопрос помечен как решенный

Ответы 9

Ответ принят как подходящий

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

Я думаю, что OP имел в виду нечто иное. Я понимаю следующий вопрос: «Как будет выглядеть описание интерфейса для одноэлементного класса в C#?»

Dirk Vollmar 15.01.2009 01:22

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

Matthew Brubaker 15.01.2009 01:25

AFAIK в C# интерфейс не может иметь статический член. Однако есть экземпляры, в которых статический член был бы полезен. Например, вам нужен КОНТРАКТ реализаций, но все эти реализации нуждаются в классификаторе, который является общим для экземпляров объекта. Это не первый раз, когда мне понадобилась такая вещь.

Lord of Scripts 01.06.2012 08:37

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

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

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

Это не ответ, почему вы не использовали функцию добавления комментариев?

AnthonyWJones 15.01.2009 00:41

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

I just want it to be known that all singeltons will have a static property named Instance of the class type. It is always there. An interface would be an explicit way to express this.

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

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

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

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

строка Key {получить; } объект SettingValue {получить; набор; } 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;
}

}

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

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

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

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

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

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, будет иметь статическое свойство Instance правильного типа:

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

    private MySingleton() { } 
}

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

Это вообще не работает. MySingleton.Instance всегда имеет значение null, а статический конструктор в конечном итоге вообще не вызывается (VS2008 .NET 3.5)

David Knight 16.12.2011 19:53

Ага. Ты прав. Доступ к свойству Instance в Singleton <T> не вызывает вызова статического конструктора в MySingleton. Довольно тривиально переставить это так, чтобы оно работало, но на самом деле, зачем вам это?

Andrew Kennan 19.12.2011 05:32

Предложение было поддержано 2 года назад

https://github.com/dotnet/csharplang/issues/1711

Но да, пока это невозможно, особенно в dotnet 3.5.

Другие вопросы по теме