有时候我有一个带默认参数的界面,我想从实现类 中调用实现方法(除了来自外部)。我也想使用它的默认参数。
但是,如果我只是按名称调用方法,则不能使用默认参数,因为它们仅在接口中定义。我可以在实现方法中重复默认规范,但这是不可取的,因为DRY和所有这些都需要(特别是编译器不会检查它们实际上是否与接口的默认值匹配!)
我通过引入一个名为_this
的成员来解决这个问题,该成员与this
相同,只是它被声明为接口类型。然后当我想使用默认参数时,我用_this
调用方法。以下是示例代码:
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();
// ...
}
}
这种模式有什么问题或以更好的方式解决问题吗? (顺便说一下,我认为这是我必须做的事情的语言缺陷)
编辑:不是Why are C# 4 optional parameters defined on interface not enforced on implementing class?的重复...我主要是询问如何解决这种语言怪癖,而不是问为什么它是这样设计的
答案 0 :(得分:4)
您有三种选择。
public interface IMovable
{
void Move(int direction, int speed);
}
public static MovableExtensions
{
public static void Move(this IMovable movable)
{
movable.Move(90, 100);
}
}
这样您就不必重复IMovable
接口中定义的默认值,接口和实现的默认值永远不会失去同步。
public class Ball : IMovable
{
void IMovable.Move(int direction, int speed)
{
}
}
public class Ball : IMovable
{
public void Move(int direction = 90, int speed = 100)
{
}
}
您的代码可能有两个用户:一个只使用IMovable
接口,另一个只使用Ball
类。可以说可能存在一个模糊的场景,其中移动IMovable
的默认值应该与移动Ball
的默认值不同,并且用户都不应该关心他们没有看到的默认值
我承认这种解释并不令人满意。如果您想了解有关语言设计原因的更多信息,请阅读Giorgi Nakeuri在您对您的问题的评论中所链接的问题和最佳答案:Why are C# 4 optional parameters defined on interface not enforced on implementing class?
答案 1 :(得分:2)
然后使用显式实现,当你将其作为接口进行转换并将其调用为接口默认值时,当您使用该类调用它时,您将获得类默认值,例如:
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();
}
}
输出
来自界面
90,100
从这个类默认为
20,10
答案 2 :(得分:0)
您可以显式转换为界面。
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();
}
}
输出:
90 100
或者您可以将您的界面转换为抽象类。
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();
}
}
输出:
90 100
答案 3 :(得分:-1)
因为您实现的方法与您的界面不完全相同,并且您的编译器不知道您想要实现该方法。
以下是你的答案。
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();
}
}