Почему дополнительные параметры С# 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
Необязательные параметры вроде макроподстановки из того, что я понимаю. Они не являются факультативными с точки зрения метода. Артефактом этого является поведение, которое вы видите, где вы получаете разные результаты, если вы передаете интерфейс.