为什么接口定义中需要参数名称?我可以在实现过程中选择新的参数名称

时间:2012-09-04 23:42:19

标签: c#

不确定这是否是一个愚蠢的问题,但我只是注意到了这一点:

public interface IActivityDao : IDao<Activity>
{
    IList<Activity> GetAllSinceSequence(long sequence, int count);
}

public class ActivityDao : AbstractNHibernateDao<Core.Domain.Activity>, IActivityDao
{        
    public IList<Activity> GetAllSinceSequence(long sequence, int maxRecords)
    {

    }
}

在我的实现中,我调用了第二个参数'maxRecords'。然而,在界面中,它被定义为“计数”。编译器仍然认为接口已实现,这很好,但可能会导致一些歧义。显然,我应该重命名其中一个参数以匹配另一个参数。

在重命名之前我玩了一下,发现了一些有趣的东西。我不允许将我的界面声明为:

public interface IActivityDao : IDao<Activity>
{
    IList<Activity> GetAllSinceSequence(long, int);
}

这只是编译器对C#语义的过度保护吗?除了使代码更具可读性之外,接口方法中的参数名称的用途是什么?在我看来,如果在实现时不强制参数名称,它会引起歧义。

6 个答案:

答案 0 :(得分:26)

接口声明中需要参数名称,以便于实现和参考。如果有人使用您的界面,方法参数的名称应该是自我记录,以便界面的使用者了解传递给方法的内容(例如,通过IntelliSense查看方法描述时)

是的,当您实现界面时,您可以根据需要为参数命名。

答案 1 :(得分:8)

历史。这可以追溯到.NET的早期阶段,当COM统治世界时。能够与COM互动是非常非常重要的,当时没有人会抛弃一切来采用全新的编程风格。

这使得.NET互操作在.NET中得到了强有力的支持。除了需要为接口方法设置命名参数外,类型库还需要它们。

有趣的角落案例永远是C ++ / CLI语言。它采用了许多C ++语法规则,包括在声明中省略参数名称的能力。换句话说,这是合法的:

    public interface class IFoo
    {
        void bar(int, long, double);
    };

类型库导出器生成此声明:

    HRESULT bar(
                    [in] long p1, 
                    [in] long p2, 
                    [in] double p3);

如果您在C#类中实现接口非常相似,则由IntelliSense自动生成:

class FooImpl : cpptemp36.IFoo {
    public void foo(int __p1, int __p2, double __p3) {
        throw new NotImplementedException();
    }
}

这让任何人都不高兴。

答案 2 :(得分:2)

我认为这是由于C#中的命名参数功能。即,您需要能够按名称指定参数,而不仅仅是默认顺序:

IActivityDao dao;
dao.GetAllSinceSequence(count: 1, sequence: 2);

当然,如果将对象强制转换为实例,参数名称会有所不同。

var concreteDao = (ActivityDao) dao;
concreteDao.GetAllSinceSequence(maxRecords: 1, sequence: 2);

答案 3 :(得分:2)

让我问你这个问题,.net框架中的其他任何地方是否允许你定义一个没有参数名称的方法签名?

在一天结束时,所有事情都是可能的,但大多数事情都是有原因的,在这种情况下,我会想象这是框架和编译器设计的限制,它真的重要吗?

你毕竟定义了一个使用合同,人们会期望它们真的存在。

答案 4 :(得分:2)

在新的代码质量世界中,实现级别的参数名称必须与接口级别相同。

在sonarqube中有一个类似的规则,“参数名称应与基本声明和其他部分定义相匹配” ,并将其称为“不兼容代码”

interface IFoo
{
  void Bar(int i);
}

class Foo : IFoo
{
  void Bar(int z) // Noncompliant, parameter name should be i
  {
  }
}

有趣的是,它引用了这份文档,没有涵盖interfacehttps://wiki.sei.cmu.edu/confluence/display/c/DCL40-C.+Do+not+create+incompatible+declarations+of+the+same+function+or+object

我个人喜欢这样的代码:

public interface IExtractor<TInput, TOutput>{
    TOutput Extract(TInput input);
}

public class CustomerExtractor : IExtractor<Order, Customer>
{
    public Customer Extract(Order order)
    {
        // ...
    }
}

但是该工具迫使我使用以下命令将其声明为紧急问题:

    public Customer Extract(Order input)
    {
        // ...
    }
在这种情况下,

inputorder的含义不同。

要消除噪音,

  • 如果不涉及DI,则将静态实用程序类用于此类(Map,Extract,Combin等)
  • 如果涉及DI,请通过添加辅助变量来欺骗工具
    public Customer Extract(Order input)
    {
       var order = input;

       // use order from here on
    }

答案 5 :(得分:1)

许多语言如C#和VB都支持named and option arguments to methods。如果接口中没有参数名称,则无法使用命名参数和可选参数。命名参数也有助于读者理解界面的意图和功能。