繁体   English   中英

使用C#“命名参数”的实际原因

[英]Practical Reasons to use C# “named arguments”

我发现C#中的“命名实参”功能真的很奇怪,因为我发现它有两个缺陷。 该书说“命名参数使您具有“以任何顺序传递参数的能力”。

我认为此C#功能存在两个缺陷:

  1. 它违反了计算机科学中的“信息隐藏”。 (即:使用该方法的最终用户需要知道参数名称和数据类型才能使用该功能。)来自Java背景,这很奇怪。 为什么将参数名称公开给用户?

  2. 容易产生歧义,这可能导致错误。 (程序员需要做更多的思考,当程序员用相同的方法名称编写方法(又名重载方法)时,问题会逐渐蔓延。当您拥有两个名称相同的方法时,您总是会得到一个“歧义”即使另一种方法具有不同数据类型的额外参数,也可以使用彼此相同的参数。我能想到的唯一解决方法是使数据类型成为“强制参数”,也就是没有默认值的参数,因此编译器可以不会感到困惑。但是,此修复程序只是绷带解决方案,可导致另一种最坏的情况(请参见下文)

迄今为止,行业内的人们是否还在使用这个概念? 如果是这样,为什么要打破这两个规则,即“在调用该方法时可以以任何顺序传递参数”?

TLDR:一个示例,通过引入一个可能的最坏情况来澄清我正在谈论的内容(尽管这两个方法很相似,但编译器选择了错误的方法调用...):

namespace ConsoleApplication1
{
    class Venusaur
    {
        static void Main(string[] args)
        {

            new Venusaur().optMethod(fourth: "s");
        }

        public void optMethod(  string third , string fourth =  "hello", int fifth = 23, string two = "w")
        {
            // what if I wanted this method to run instead of the method below me
            Console.WriteLine("did not execute");
        }


        public void optMethod(string third = "Byte", string fourth = "hello",  int fifth = 4)
        {
            // But this method ran instead
            Console.WriteLine("run");

        }


    }
}

命名参数是增加的另一项技术,可简化与COM(和类似技术)的互操作性。

采用使用COM打开Word文档的方法

Document Open(
    [In] ref object FileName, 
    [In, Optional] ref object ConfirmConversions, 
    [In, Optional] ref object ReadOnly, 
    [In, Optional] ref object AddToRecentFiles, 
    [In, Optional] ref object PasswordDocument, 
    [In, Optional] ref object PasswordTemplate, 
    [In, Optional] ref object Revert, 
    [In, Optional] ref object WritePasswordDocument, 
    [In, Optional] ref object WritePasswordTemplate, 
    [In, Optional] ref object Format, 
    [In, Optional] ref object Encoding, 
    [In, Optional] ref object Visible, 
    [In, Optional] ref object OpenAndRepair, 
    [In, Optional] ref object DocumentDirection, 
    [In, Optional] ref object NoEncodingDialog, 
    [In, Optional] ref object XMLTransform
);

它具有不少于16个参数,其中15个是可选的。

如果您想指定XMLTransform参数但不关心其余部分怎么办?

您将必须使用位置参数指定其余部分。 使用命名参数,调用将简单地变为:

doc.Open("somefilename.doc", XMLTransform: xxx);

除了dynamic和其他一些功能外,它并不是解决许多问题的好方法,但是当您使用的API严重依赖具有很多参数的方法时,其中大多数是可选的,命名参数说得通。

是的,您可以指定乱序的参数。 这并不意味着它是一个好主意,也不意味着它可以解决某人确实遇到的问题。

我发现你的第一个论点完全是似是而非。 不管是否喜欢,参数名称都是每种方法语义的一部分,尤其是对于抽象类和将在子类中覆盖的方法。 参数的名称是向用户告知该方法的语义的关键信号,并且每个参数在该语义中的作用。 此外,对于理解整个类层次结构的语义而言,至关重要的是,参数名称必须一致,并且不受每个级别的各个程序员的异想天开。

我发现您的第二个论点完全难以理解。 如果您在这里确实有一个有效的观点,我建议您重写此观点以提高清晰度。

也就是说,我很少在方法调用中使用命名参数。 接受两个以上相同类型连续参数的方法除外。 在这种情况下,我想为它们命名,以便作为代码的未来读者,我实际上可以解密该方法的用法,而不必不断地悬停以查看智能感知。

1)我不知道“信息隐藏”在哪里; 方法签名是您要求最终用户给您的。 他显然需要知道数据类型和名称,以消除参数为何指代什么的歧义。 而且,他仍然不知道您要使用那些您要的参数做什么(也许什么也没有),因此需要隐藏的内容仍然隐藏。

2)对于两个仅因参数数量不同而导致的重载,这里的问题是一个不好的选择,再加上省略某些参数(由可选参数提供)的能力,会使您失去区分它们的“好处”(除非您给出所有参数)

为interop场景引入了(部分)动态命名的参数; 例如,在Office Automation中,在C#3中您需要添加一堆Type.Missing参数,然后在C#4中,您只需提供所需/需要的参数即可。

关于COM互操作的要点是最重要的。

如果我在方法签名中有一个布尔参数想要使用,但是我没有明显的变量可以使用,我个人倾向于使用它。 例:

我觉得更具可读性

var isSuccessful = myObject.Method(isRecursive: true)

然后

var isSuccessful = myObject.Method(true);

最终您可以使用更详细的语法

var isRecursive = true;
var isSuccessful = myObject.Method(isRecursive);

避免命名参数。

这样调用方法的明显缺点是,如果由于某种原因方法的签名发生更改,您的代码将不再生成。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM