Utilisation de c # 4.0 - construction d'une interface et d'une classe qui implémente l'interface. Je veux déclarer un paramètre facultatif dans l'interface et le faire refléter dans la classe. Donc, j'ai ce qui suit:
public interface IFoo
{
void Bar(int i, int j=0);
}
public class Foo
{
void Bar(int i, int j=0) { // do stuff }
}
Cela compile, mais il ne semble pas correct. L'interface doit avoir les paramètres facultatifs, sinon elle ne se reflète pas correctement dans la signature de la méthode d'interface.
Dois-je ignorer le paramètre facultatif et utiliser simplement un type nullable? Ou cela fonctionnera-t-il comme prévu sans effets secondaires ni conséquences?
Vous pouvez envisager l'alternative des paramètres pré-optionnels:
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);
}
}
Si vous n'aimez pas l'apparence d'une nouvelle fonctionnalité de langue, vous n'êtes pas obligé de l'utiliser.
Ce qui est vraiment étrange, c'est que la valeur que vous mettez pour le paramètre facultatif dans l'interface fait réellement une différence. Je suppose que vous devez vous demander si la valeur est un détail d'interface ou un détail d'implémentation. J'aurais dit le dernier mais les choses se comportent comme le premier. Le code suivant sort par exemple 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);
}
}
}
Ce qui est plutôt intéressant, c'est que si votre interface rend un paramètre optionnel, la classe qui l'implémente n'a pas à faire de même:
// 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);
}
}
}
Ce qui semble être une erreur cependant, c'est que si vous implémentez l'interface explicitement, la valeur que vous donnez dans la classe pour la valeur facultative est inutile. Comment dans l'exemple suivant pouvez-vous utiliser la valeur 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);
}
}
}
Eric Lippert a écrit une série intéressante sur ce sujet exact: Cas d'angle d'argument optionnels
Vous n'avez pas à rendre le paramètre facultatif dans l'implémentation. Votre code aura alors un peu plus de sens:
public interface IFoo
{
void Bar(int i, int j = 0);
}
public class Foo
{
void Bar(int i, int j) { // do stuff }
}
De cette façon, la valeur par défaut est sans ambiguïté. En fait, je suis presque sûr que la valeur par défaut dans l'implémentation n'aura aucun effet, car l'interface fournit une valeur par défaut pour cela.
Et quelque chose comme ça?
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 */ }
}
La chose à considérer est ce qui se passe lorsque des frameworks Mocking sont utilisés, qui fonctionnent en fonction de la réflexion de l'interface. Si des paramètres facultatifs sont définis sur l'interface, la valeur par défaut serait transmise en fonction de ce qui est déclaré dans l'interface. Un problème est que rien ne vous empêche de définir différentes valeurs facultatives dans la définition.
Regarde de côté, cela fera exactement ce que tu as envie d'accomplir.