Дополнительные параметры для интерфейсов
Использование С# 4.0 - создание интерфейса и класса, реализующего интерфейс. Я хочу объявить необязательный параметр в интерфейсе и отразить его в классе. Итак, у меня есть следующее:
public interface IFoo
{
void Bar(int i, int j=0);
}
public class Foo
{
void Bar(int i, int j=0) { // do stuff }
}
Это компилируется, но выглядит не так. Интерфейс должен иметь необязательные параметры, поскольку в противном случае он не будет правильно отражать подпись подписи интерфейса.
Должен ли я пропустить необязательный параметр и просто использовать тип с нулевым значением? Или это будет работать по назначению без каких-либо побочных эффектов или последствий?
Ответы
Ответ 1
Вы можете рассмотреть альтернативу дополнительных опций:
public interface IFoo
{
void Bar(int i, int j);
}
public static class FooOptionalExtensions
{
public static void Bar(this IFoo foo, int i)
{
foo.Bar(i, 0);
}
}
Если вам не нравится внешний вид новой языковой функции, вам не нужно ее использовать.
Ответ 2
Что действительно странно, так это то, что значение, которое вы указываете для необязательного параметра в интерфейсе, действительно имеет значение. Я полагаю, у вас есть вопрос, является ли значение деталью интерфейса или реализацией. Я бы сказал последнее, но все ведет себя как первый. Например, следующий код выводит 1 0 2 5 3 7.
// Output:
// 1 0
// 2 5
// 3 7
namespace ScrapCSConsole
{
using System;
interface IMyTest
{
void MyTestMethod(int notOptional, int optional = 5);
}
interface IMyOtherTest
{
void MyTestMethod(int notOptional, int optional = 7);
}
class MyTest : IMyTest, IMyOtherTest
{
public void MyTestMethod(int notOptional, int optional = 0)
{
Console.WriteLine(string.Format("{0} {1}", notOptional, optional));
}
}
class Program
{
static void Main(string[] args)
{
MyTest myTest1 = new MyTest();
myTest1.MyTestMethod(1);
IMyTest myTest2 = myTest1;
myTest2.MyTestMethod(2);
IMyOtherTest myTest3 = myTest1;
myTest3.MyTestMethod(3);
}
}
}
Интересно, что если ваш интерфейс делает параметр необязательным, то класс, реализующий его, не должен делать то же самое:
// Optput:
// 2 5
namespace ScrapCSConsole
{
using System;
interface IMyTest
{
void MyTestMethod(int notOptional, int optional = 5);
}
class MyTest : IMyTest
{
public void MyTestMethod(int notOptional, int optional)
{
Console.WriteLine(string.Format("{0} {1}", notOptional, optional));
}
}
class Program
{
static void Main(string[] args)
{
MyTest myTest1 = new MyTest();
// The following line won't compile as it does not pass a required
// parameter.
//myTest1.MyTestMethod(1);
IMyTest myTest2 = myTest1;
myTest2.MyTestMethod(2);
}
}
}
Однако ошибкой кажется то, что если вы реализуете интерфейс явно, то значение, которое вы дадите в классе для необязательного значения, будет бессмысленным. Как в следующем примере вы можете использовать значение 9?
// Optput:
// 2 5
namespace ScrapCSConsole
{
using System;
interface IMyTest
{
void MyTestMethod(int notOptional, int optional = 5);
}
class MyTest : IMyTest
{
void IMyTest.MyTestMethod(int notOptional, int optional = 9)
{
Console.WriteLine(string.Format("{0} {1}", notOptional, optional));
}
}
class Program
{
static void Main(string[] args)
{
MyTest myTest1 = new MyTest();
// The following line won't compile as MyTest method is not available
// without first casting to IMyTest
//myTest1.MyTestMethod(1);
IMyTest myTest2 = new MyTest();
myTest2.MyTestMethod(2);
}
}
}
Эрик Липперт написал интересную серию на эту тему: дополнительные аргументы
Ответ 3
Вам не нужно указывать параметр в реализации. Тогда ваш код будет иметь несколько больше смысла:
public interface IFoo
{
void Bar(int i, int j = 0);
}
public class Foo
{
void Bar(int i, int j) { // do stuff }
}
Таким образом, это однозначно, что значение по умолчанию. На самом деле, я уверен, что значение по умолчанию в реализации не будет иметь никакого эффекта, так как интерфейс предоставляет по умолчанию для него.
Ответ 4
Как насчет этого?
public interface IFoo
{
void Bar(int i, int j);
}
public static class IFooExtensions
{
public static void Baz(this IFoo foo, int i, int j = 0)
{
foo.Bar(i, j);
}
}
public class Foo
{
void Bar(int i, int j) { /* do stuff */ }
}
Ответ 5
То, что нужно учитывать, - это то, что происходит при использовании Mocking-фреймворков, которые работают на основе отражения интерфейса.
Если на интерфейсе определены дополнительные параметры, значение по умолчанию будет передано на основе того, что объявлено в интерфейсе.
Одна из проблем заключается в том, что нет ничего, что помешает вам установить различные необязательные значения в определении.
Ответ 6
Выглядит в сторону, это будет делать то, что похоже на то, что вы хотите выполнить.