Почему C # не позволяет статическим методам реализовать интерфейс?

Я нашел приведенный выше фрагмент кода by @earino довольно полезным - но мне нужно было что-то, что могло бы непрерывно сглаживать поток значений, поэтому я реорганизовал его на это:

def exponential_moving_average(period=1000):
    """ Exponential moving average. Smooths the values in v over ther period. Send in values - at first it'll return a simple average, but as soon as it's gahtered 'period' values, it'll start to use the Exponential Moving Averge to smooth the values.
    period: int - how many values to smooth over (default=100). """
    multiplier = 2 / float(1 + period)
    cum_temp = yield None  # We are being primed

    # Start by just returning the simple average until we have enough data.
    for i in xrange(1, period + 1):
        cum_temp += yield cum_temp / float(i)

    # Grab the timple avergae
    ema = cum_temp / period

    # and start calculating the exponentially smoothed average
    while True:
        ema = (((yield ema) - ema) * multiplier) + ema

, и я использую его как это:

def temp_monitor(pin):
    """ Read from the temperature monitor - and smooth the value out. The sensor is noisy, so we use exponential smoothing. """
    ema = exponential_moving_average()
    next(ema)  # Prime the generator

    while True:
        yield ema.send(val_to_temp(pin.read()))

(где pin.read () создает следующее значение, которое я хотел бы использовать).

432
задан Otiel 6 July 2012 в 07:14
поделиться

13 ответов

Принятие Вас спрашивает, почему Вы не можете сделать этого:

public interface IFoo {
    void Bar();
}

public class Foo: IFoo {
    public static void Bar() {}
}

Это не имеет смысла мне, семантически. Методы, определенные в интерфейсе, должны быть там для определения контракта для взаимодействия с объектом. Статические методы не позволяют Вам взаимодействовать с объектом - при нахождении в положении, где реализация могла быть сделана статичной, Вы, возможно, должны спросить себя, если тот метод действительно принадлежит интерфейса.

<час> Для реализации примера я дал бы Животному свойство константы, которое все еще позволит ему быть полученным доступ от статического контекста и возврата, которые оценивают в реализации.
public class Animal: IListItem {
    /* Can be tough to come up with a different, yet meaningful name!
     * A different casing convention, like Java has, would help here.
     */
    public const string AnimalScreenName = "Animal";
    public string ScreenName(){ return AnimalScreenName; }
}

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

212
ответ дан Chris Marasti-Georg 6 July 2012 в 07:14
поделиться

Я думаю, близорукость.

Первоначально разработанные интерфейсы предназначались только для использования с экземплярами класса

IMyInterface val = GetObjectImplementingIMyInterface();
val.SomeThingDefinedinInterface();

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

(отвечает на комментарий :) Я полагаю, что для его изменения сейчас потребуется изменить CLR, что приведет к несовместимости с существующими сборками.

14
ответ дан James Curran 6 July 2012 в 07:14
поделиться

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

Предположим, у нас есть параметр типа в универсальном методе, и нам нужно сделать с ним некоторую операцию. Мы не хотим мгновенно, потому что мы не знаем конструкторов.

Например:

Repository GetRepository<T>()
{
  //need to call T.IsQueryable, but can't!!!
  //need to call T.RowCount
  //need to call T.DoSomeStaticMath(int param)
}

...
var r = GetRepository<Customer>()

К сожалению, я могу придумать только «некрасивые» альтернативы:

  • Использовать отражение [1118 Уродлив и бьет идею интерфейсов и полиморфизма.

  • Создать полностью отдельный фабричный класс

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

  • Создавать и вызывать нужный интерфейсный метод

    Это может быть сложно реализовать, даже если мы контролируем источник для классов, используемых в качестве общих параметров. Причина в том, что, например, нам может потребоваться, чтобы экземпляры были только в хорошо известном состоянии «подключен к БД».

Пример:

public class Customer 
{
  //create new customer
  public Customer(Transaction t) { ... }

  //open existing customer
  public Customer(Transaction t, int id) { ... }

  void SomeOtherMethod() 
  { 
    //do work...
  }
}

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

public class Customer: IDoSomeStaticMath
{
  //create new customer
  public Customer(Transaction t) { ... }

  //open existing customer
  public Customer(Transaction t, int id) { ... }

  //dummy instance
  public Customer() { IsDummy = true; }

  int DoSomeStaticMath(int a) { }

  void SomeOtherMethod() 
  { 
    if(!IsDummy) 
    {
      //do work...
    }
  }
}

Это, очевидно, некрасиво, а также излишне усложняет код для всех других методов. Очевидно, что это тоже не элегантное решение!

89
ответ дан Ian Boyd 6 July 2012 в 07:14
поделиться

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

1
ответ дан Daniel Auger 6 July 2012 в 07:14
поделиться

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

0
ответ дан mackenir 6 July 2012 в 07:14
поделиться

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

3
ответ дан Scott Langham 6 July 2012 в 07:14
поделиться

Интерфейсы являются абстрактными наборами определенной доступной функциональности.

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

, Если бы методы были определены столь же статичные, класс, реализовывая интерфейс столь не инкапсулировался бы, как это могло быть. Инкапсуляция является хорошей вещью бороться за в объектно-ориентированном проектировании (я не войду, почему, можно считать что здесь: http://en.wikipedia.org/wiki/Object-oriented ). Поэтому статические методы не разрешены в интерфейсах.

1
ответ дан Jeff Yates 6 July 2012 в 07:14
поделиться

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

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

Его также вероятный, что compilier, который соответствовал этому требованию, потеряет некоторые оптимизации, которые могут идти с более строгим разделением между методами экземпляра и статическими методами.

3
ответ дан AnthonyWJones 6 July 2012 в 07:14
поделиться

Поскольку интерфейсы находятся в структуре наследования, и статические методы не наследовались хорошо.

3
ответ дан Joel Coehoorn 6 July 2012 в 07:14
поделиться

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

, Как Вы назвали бы его??

<час>
public interface MyInterface { void MyMethod(); }
public class MyClass: MyInterface
{
    public static void MyMethod() { //Do Something; }
}

 // inside of some other class ...  
 // How would you call the method on the interface ???
    MyClass.MyMethod();  // this calls the method normally 
                         // not through the interface...

    // This next fails you can't cast a classname to a different type... 
    // Only instances can be Cast to a different type...
    MyInterface myItf = MyClass as MyInterface;  
9
ответ дан Charles Bretana 6 July 2012 в 07:14
поделиться

Моя (упрощенная) техническая причина - то, что статические методы не находятся в vtable, и сайт вызова выбран во время компиляции. Это - та же причина, у Вас не может быть переопределения или виртуальных статических участников. Для получения дополнительной информации Вам были бы нужны градиент CS или зубрила компилятора - из которых я не ни один.

По политической причине, я буду кавычка Eric Lippert (кто зубрила компилятора и держит бакалавра математических наук, Информатику и Прикладную математику из Университета Уотерлу (источник: LinkedIn):

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

Примечание, что Lippert действительно оставляет комнату для так называемого метода типа:

таким образом, метод, связанный с типом (как помехи), который не берет не допускающий NULL-значения “this” аргумент (в отличие от экземпляра или виртуальный), но тот, где названный метод зависел бы от созданного типа T (в отличие от помех, которые должны быть определимыми во время компиляции).

, но должен все же быть убежден в его полноценности.

164
ответ дан yoyo 6 July 2012 в 07:14
поделиться

Интерфейсы определяют поведение объекта.

Статические методы не определяют поведение объекта, но поведение, которое влияет на объект в некотором роде.

14
ответ дан John Kraft 6 July 2012 в 07:14
поделиться

Для предоставления примера, где я пропускаю или статическую реализацию методов интерфейса или что Mark Brackett представил как "так называемый метод типа":

При чтении из устройства хранения данных базы данных, у нас есть универсальный класс DataTable, который обрабатывает чтение из таблицы любой структуры. Определенная информация всей таблицы помещается в один класс на таблицу, которая также содержит данные для одной строки от DB и которая должна реализовать интерфейс IDataRow. Включенный в IDataRow описание структуры таблицы для чтения из базы данных. DataTable должен попросить datastructure от IDataRow прежде, чем читать из DB. В настоящее время это похоже:

interface IDataRow {
  string GetDataSTructre();  // How to read data from the DB
  void Read(IDBDataRow);     // How to populate this datarow from DB data
}

public class DataTable<T> : List<T> where T : IDataRow {

  public string GetDataStructure()
    // Desired: Static or Type method:
    // return (T.GetDataStructure());
    // Required: Instantiate a new class:
    return (new T().GetDataStructure());
  }

}

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

3
ответ дан 6 July 2012 в 18:14
поделиться
  • 1
    Отличное решение. Существует ли способ заставить его работать, если Вы хотите отобразить заливку на страну также? – Peter Ellis 6 July 2012 в 00:20
Другие вопросы по тегам:

Похожие вопросы: