我发现C#中的这个功能“命名参数”非常奇怪,因为我看到了它的两个缺陷。该书说“命名参数赋予你”以任何顺序传递参数的能力“。
我认为这个C#功能存在两个缺陷:
它违反了计算机科学中的“信息隐藏”。 (即:使用该方法的最终用户需要知道参数名称和数据类型才能使用该功能。)来自Java背景,这很奇怪。为什么要将参数名称暴露给用户的末尾?
容易出现歧义,导致错误。 (当程序员编写使用相同方法名称(也称为重载方法)的方法时,程序员需要进行额外的思考和问题。当你有两个同名的方法时,你总会得到一个“调用是不明确的”即使另一个方法具有不同数据类型的额外参数,彼此具有相同的参数。我能想到的唯一修复是使数据类型成为“强制参数”,也就是没有默认值的参数,因此编译器会不要混淆。但是这个修复只是导致另一个最坏情况的绷带解决方案(见下文)
业内人士甚至直到今天都使用这个概念吗?如果是这样,为什么要打破两个规则“在调用方法时能够以任何顺序传递参数”?
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");
}
}
}
答案 0 :(得分:7)
命名参数是为了使COM(和类似技术)的互操作性更容易添加的另一项技术。
选择method to open a Word document using COM:
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 :(得分:3)
我发现你的第一个论点完全似是而非。喜欢或不喜欢参数的名称是每个方法的语义的一部分,特别是对于将在子类中重写的抽象类和方法。参数的名称是关于该方法的语义的方法的用户以及该语义中的每个参数角色的关键信号。此外,理解整个类层次结构中的语义是必不可少的,参数名称必须一致,并且不受每个级别的各个程序员的突发奇想。
我发现你的第二个论点完全无法理解。如果你在这里确实有一个有效点,我建议你重写一下以获得更大的清晰度。
那就是说,我很少在我的方法调用中使用命名参数;例外情况是接受两个以上相同类型的连续参数的方法。在这种情况下,我喜欢给它们命名,以便我作为代码的未来读者,实际上可以破译方法的使用而不必经常盘旋以看到智能感。
答案 2 :(得分:1)
1)我不明白那里有“信息隐藏”的地方;方法签名是您要求最终用户给您的方法。他显然需要知道数据类型和名称,以消除为什么参数指的是什么。此外,他仍然不知道你要对那些你要求的参数做什么(可能没什么)所以需要隐藏的东西仍然是隐藏的。
2)这里的问题是两个重载的错误选择,只有参数的数量不同,结合省略某些参数的能力(由可选参数提供)会使你失去区分它们的“好处”(除非你提出所有论据)
命名参数(部分)引入了动态的互操作场景;例如,使用Office自动化,在C#3中,您需要添加一堆Type.Missing
个参数,然后在C#4中,您可以只提供您想要/需要的那些。
答案 3 :(得分:0)
关于COM互操作的观点是最重要的。
我个人倾向于使用它,如果我想在方法签名中使用布尔参数,但我没有明显的变量可以使用。 例如:
我发现更具可读性
var isSuccessful = myObject.Method(isRecursive: true)
然后
var isSuccessful = myObject.Method(true);
最终你可以更详细的语法
var isRecursive = true;
var isSuccessful = myObject.Method(isRecursive);
以避免命名参数。
调用这样的方法的明显缺点是,如果由于某种原因,方法的签名发生了变化,那么代码将不再构建。