Почему дополнительные параметры С# 4, определенные на интерфейсе, не выполняются при реализации класса?

Я заметил, что с дополнительными параметрами в С# 4, если вы укажете параметр как необязательный на интерфейсе, НЕ НЕОБХОДИМО сделать этот параметр необязательным для любого класса реализации:

public interface MyInterface
{
    void TestMethod(bool flag=false);
}

public class MyClass : MyInterface
{
    public void TestMethod(bool flag)
    {
        Console.WriteLine(flag);
    }
}

и поэтому:

var obj = new MyClass();        
obj.TestMethod(); // compiler error

var obj2 = new MyClass() as MyInterface;
obj2.TestMethod(); // prints false

Кто-нибудь знает, почему дополнительные параметры предназначены для работы таким образом?

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

С другой стороны, это отключение означает, что вы не всегда можете использовать конкретный класс и интерфейс взаимозаменяемо. Это, конечно, не будет проблемой, если значение по умолчанию указано в реализации, но тогда, если вы раскрываете свой конкретный класс в качестве интерфейса (используя некоторую среду IOC для инъекции конкретного класса, например), то действительно нет точка имеет значение по умолчанию, поскольку вызывающий должен всегда предоставлять его в любом случае.

Ответ 1

UPDATE: Этот вопрос был предметом моего блога 12 мая 2011 года. Спасибо за отличный вопрос!

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

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


// in metadata:
public class B 
{ 
    public void TestMethod(bool b) {}
}

// in source code
interface MyInterface 
{ 
    void TestMethod(bool b = false); 
}
class D : B, MyInterface {}
// Legal because D base class has a public method 
// that implements the interface method

Как автор D должен сделать эту работу? Требуются ли в вашем мире призывы к автору B по телефону и попросить их отправить им новую версию B, которая заставляет метод иметь необязательный параметр?

Это не собирается летать. Что делать, если два человека вызывают автора B, и один из них хочет, чтобы значение по умолчанию было истинным, и один из них хочет, чтобы он был ложным? Что, если автор B просто откажется играть?

Возможно, в этом случае они должны будут сказать:

class D : B, MyInterface 
{
    public new void TestMethod(bool b = false)
    {
        base.TestMethod(b);
    }
}

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

Ответ 2

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

Вызов obj2.TestMethod(); заменяется на obj2.TestMethod(false);, когда код С# компилируется в IL, а не в JIT-время.

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

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

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

Ответ 3

Поскольку параметры по умолчанию разрешены во время компиляции, а не во время выполнения. Значения по умолчанию не относятся к вызываемому объекту, а относятся к типу ссылочного типа, который он вызывает.

Ответ 4

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