C# 避免重复接口的默认设置

C# 避免重复接口的默认设置,c#,C#,我有一个带有默认参数的接口,我想从实现类的内部调用实现方法(除了从外部调用)。我还想使用它的默认参数 但是,如果我只是按名称调用该方法,我就不能使用默认参数,因为它们仅在接口中定义。我可以在实现方法中重复默认规范,但由于DRY和所有这些细节,这不太可能(尤其是编译器不会检查它们是否与接口的默认值匹配!) 我通过引入一个名为\u this的成员来解决这个问题,该成员与this相同,只是声明为接口类型。然后,当我想使用默认参数时,我使用\u this调用该方法。下面是示例代码: public int

我有一个带有默认参数的接口,我想从实现类的内部调用实现方法(除了从外部调用)。我还想使用它的默认参数

但是,如果我只是按名称调用该方法,我就不能使用默认参数,因为它们仅在接口中定义。我可以在实现方法中重复默认规范,但由于DRY和所有这些细节,这不太可能(尤其是编译器不会检查它们是否与接口的默认值匹配!)

我通过引入一个名为
\u this
的成员来解决这个问题,该成员与
this
相同,只是声明为接口类型。然后,当我想使用默认参数时,我使用
\u 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();

        // ...
    }
}
这种模式有什么问题吗,或者有什么更好的解决问题的方法吗?(顺便说一句,我认为这是语言中的一个缺陷,我必须这样做)


编辑:不是重复的……我主要是问如何解决这个语言怪癖,而不是问为什么它是这样设计的

,因为您实现的方法与您的接口不完全相同,并且您的编译器不知道您要实现该方法

这是你的答案

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();
    }
}

你有三个选择

使用扩展方法作为默认值 显式实现接口 这样,您就不必重复在
IMovable
接口中定义的默认值,并且接口和实现的默认值永远不会不同步

public class Ball : IMovable
{    
    void IMovable.Move(int direction, int speed)
    {
    }
}
重复默认参数 您的代码可能有两个用户:一个用户只使用
IMovable
界面,另一个用户只使用
Ball
类。可以说,可能存在一个模糊的场景,其中移动
IMovable
的默认值应该不同于移动
Ball
的默认值,并且两个用户都不应该有关心他们没有看到的默认值


我承认这一解释并不令人满意。如果您想了解更多关于语言为何如此设计的信息,请阅读Giorgi Nakuri在其对您的问题的评论中链接的问题和首要答案:

您可以显式转换到界面

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
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
90 100

然后使用显式实现,当您强制转换并调用它作为接口时,您将获得接口默认值,当您使用类调用它时,您将获得类默认值,例如:

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();
    }
}
以及输出

从接口
90100
从该类中选择默认值
20,10


相关的可能重复:您不需要重复默认值,在我的示例中,您可以注意到显式实现是如何获取接口参数的,而在显式实现中,我甚至没有默认值。这并不会降低问题的趣味性,但将参数值放在接口上让我深感困扰。t对我来说,值取决于实现,因此不应该由接口强制执行。我认为重载更合适。不过,这是一个有趣的角落case@KooKiz,我有点同意,但是可以通过将接口中的所有可选参数指定为默认值
null
然后,每个实现都可以使用<代码>?>代码>默认为一个实际的默认值……例如,对于接口中的<代码> int?方向= null <代码>,实现可以从<代码>方向=方向(90)/代码>默认为90。不正确!编译器认为它是一个实现。(不复制默认值)!证明我可以通过接口调用它。无论我是否省略默认值,复制它们,甚至更改它们(!!!),C#将其识别为interfaceOh的实现!!谢谢。顺便说一句,如果我不解释args,它将在Visual Studio中出错。这就是我试图通过使用_this来避免的。如果是这样,为什么不将接口转换为抽象类并实现不带参数的Move方法,即使用defau调用Movelt参数90和100。此外,我认为这不是语言中的缺陷,因为默认参数是在编译时解析的,因此编译器只能确保在使用接口类型时使用默认参数。我喜欢抽象类的想法,但会阻止我从更有用的基类派生没有必要显式地实现接口……即使我不重复这个过程,编译器也会识别它defaults@JoelFan我知道这一点。突出的一点是,如果你显式地实现了接口,那么接口默认值和实现默认值不可能不同步,仅仅是因为e没有实现指定的默认值。我的意思是,即使没有显式实现接口,我也可以在实现中省略默认值……我不知道显式实现会给我带来多少选择,但明确地说,显式实现应该是我可以使用的方式((Imovable)this)在任何地方,即使没有显式实现接口,但这正是我要尝试的avoid@JoelFan但IMovable是一个接口,它没有内容或定义,它没有意义,你需要定义接口,接口只指示某个对象包含某些方法或属性,没有more@JoelFan我说不行但是,嘿,你需要定义这个方法,这就是你正在做的,它是一个接口的定义,我不明白为什么它在这一点上是错误的。