Avoid repeating the defaults of an interface
有时我有一个带有默认参数的接口,我想从实现类内部(除了从实现类外部)调用实现方法。我还想使用它的默认参数。
但是,如果我只是按名称调用方法,我就不能使用默认参数,因为它们只在接口中定义。我可以在实现方法中重复默认的规范,但这是不可取的,因为Dry和所有需要的(特别是编译器不会检查它们是否与接口的默认值匹配!)
我通过引入一个名为
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | public interface IMovable { // I define the default parameters in only one place void Move(int direction = 90, int speed = 100); } public class Ball: IMovable { // Here is my pattern private readonly IMovable _this; public Ball() { // Here is my pattern _this = this; } // I don't want to repeat the defaults from the interface here, e.g. // public void Move(int direction = 90, int speed = 100) public void Move(int direction, int speed) { // ... } public void Play() { // ... //This would not compile //Move(); // Now I can call"Move" using its defaults _this.Move(); // ... } } |
这种模式有什么问题吗,或者用更好的方法解决问题?(顺便说一句,我认为这是语言上的一个缺陷,我必须这样做)
编辑:不重复为什么在接口上定义的C 4可选参数没有在实现类上强制执行?…我主要是问如何解决这种语言怪癖,而不是问为什么它是这样设计的。
你有三个选择。
使用扩展方法作为默认值1 2 3 4 5 6 7 8 9 10 11 12 | public interface IMovable { void Move(int direction, int speed); } public static MovableExtensions { public static void Move(this IMovable movable) { movable.Move(90, 100); } } |
号显式实现接口
这样,您就不必重复在
1 2 3 4 5 6 | public class Ball : IMovable { void IMovable.Move(int direction, int speed) { } } |
重复默认参数
1 2 3 4 5 6 | public class Ball : IMovable { public void Move(int direction = 90, int speed = 100) { } } |
。
您的代码可能有两个用户:一个只使用
我承认这个解释不太令人满意。如果你想要更多关于语言为什么是这样设计的信息,请阅读问题和答案:为什么在接口上定义的C 4可选参数在实现类上没有强制执行?
然后使用显式实现,当您强制转换并将其作为接口调用时,您将获得接口默认值,当您使用类调用它时,您将获得类默认值,例如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | public class Ball : IMovable { //this uses the interface defaults //notice how you dont need to define the default values again //they are only specified once, in the interface definition void IMovable.Move(int direction, int speed) { Debug.WriteLine(direction +"," + speed); } //now for the specific case of this class you can have your own defaults //or none, just what ever fits your needs public void Move(int direction = 20, int speed = 10) { Debug.WriteLine(direction +","+ speed); } public void Play() { Debug.WriteLine("From interface"); ((IMovable) this).Move(); Debug.WriteLine("From this class defaults"); Move(); } } |
。
以及输出
From Interface
90, 100
From this class defaults
20, 10
号
可以显式转换到接口。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | using System; using System.IO; using System.Threading.Tasks; public class Test { public static void Main() { var t = new Test1(); t.Play(); } } public interface IMovable { // I define the default parameters in only one place void Move(int direction = 90, int speed = 100); } public class Test1 : IMovable{ public void Move (int direction, int speed) { Console.Write($"{direction} {speed}"); } public void Play (){ ((IMovable)this).Move(); } } |
输出:
1 | 90 100 |
。
或者可以将接口转换为抽象类。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | using System; using System.IO; using System.Threading.Tasks; public class Test { public static void Main() { var t = new Test1(); t.Play(); } } public abstract class IMovable { // I define the default parameters in only one place public abstract void Move(int direction, int speed); public void Move(){ this.Move(90, 100); } } public class Test1 : IMovable{ public virtual void Move(int direction, int speed){ Console.Write($"{direction} {speed}"); } public void Play (){ this.Move(); } } |
。
输出:
1 | 90 100 |
。
因为您实现的方法与接口不完全相同,并且编译器不知道您想要实现该方法。
这是你的答案。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | public interface IMovable { void Move(int direction = 90, int speed = 100); } public class Ball : IMovable { // the method you want to implement from interface // MUST same with interface's declaration public void Move(int direction = 90, int speed = 100) { // ... } public void Play() { Move(); } } |