Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/336.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 为什么C“只允许方法的最后一个参数为”;“可变长度”;_C#_.net_Methods_Parameters - Fatal编程技术网

C# 为什么C“只允许方法的最后一个参数为”;“可变长度”;

C# 为什么C“只允许方法的最后一个参数为”;“可变长度”;,c#,.net,methods,parameters,C#,.net,Methods,Parameters,据我所知,C#只允许方法的最后一个参数为“可变长度”,例如: T f(params string[] a, params object[] b); tf(aa,参数B[]B)允许如果您有ar。。。。B x,y,z您可以像调用f(r,x,y,z)一样调用f。为什么C#没有定义以下内容: T f(params A[] a, params B[] b) 因为编译器如何知道第一个参数的变量参数何时停止 请告诉我方法体内部应该包含什么argOne和argTwo: void Foo( params ob

据我所知,C#只允许方法的最后一个参数为“可变长度”,例如:

T f(params string[] a, params object[] b);
tf(aa,参数B[]B)
允许如果您有
ar。。。。B x,y,z
您可以像调用f(r,x,y,z)一样调用f。为什么C#没有定义以下内容:

T f(params A[] a, params B[] b)

因为编译器如何知道第一个参数的变量参数何时停止

请告诉我方法体内部应该包含什么
argOne
argTwo

void Foo( params object[] argOne, params object[] argTwo )
{
    // whatever
} 

Foo( 1, false, "Hello", new object(), 2.3 );

因为模棱两可。如果你去做了:

T f(params int[] a, params int[] b)
你打电话来:

f(1, 2, 3, 4)
编译器如何知道一个从哪里开始,另一个从哪里开始?您可能会争辩说,这样的情况仍然可以标记为编译错误,并且仍然允许明确的情况继续下去,但是使用继承可能会变得复杂,不值得这样做。而是传递两个数组。我想不出有什么情况值得使用两个参数数组,即使这样,它也是语法上的糖分。它和仅仅使用数组没有区别

(另一个例子:

T f(params string[] a, params object[] b);

字符串
继承自
对象
。这仍然是不明确的…

它会提出问题并导致冲突

例如,假设
B
继承自
A

编译器如何理解:

f(A1, A2, B1, B2)
它是指
f({A1,A2},{B1,B2})
还是
f({A1,A2,B1},{B2})

我认为理论上,编译器可以是智能的,可以检测冲突。

然而,最初当.NET和C#本身被设计时,其想法是试图避免像这样不含糊和棘手的情况。

有许多边缘情况使这成为一个不可能的特性。考虑这个例子:

public static class Coolifier
{
  public static void BeCool<A,B>(params A[] a, params B[] b)
  {
  }
}

Coolifier.BeCool<string,string> ("I", "don't", "work.", "DO", "I", "?");
公共静态类冷却器
{
公共静态void BeCool(参数A[]A,参数B[]B)
{
}
}
cooliver.BeCool(“我”、“不”、“工作”、“做”、“我”和“?”);

该示例显示了如何无法知道第一个参数[]在何处结束,下一个参数从何处开始。

因为要确定何时实际允许这种构造太复杂了。
(当通话内容明确时)
虽然可以制定一套好的规则,但这些规则相当复杂,难以理解。人们最终会问,如果案例X有微妙的歧义,为什么它不起作用

例如:

T f(params string[] a, params object[] b);
  • 这两种类型都不能是接口或泛型参数
  • 如果一种类型是枚举或数字类型,则另一种类型必须是除
    对象
    枚举
  • 如果一种类型是委托,则另一种类型也不能是委托类型(或
    对象
    委托
    ,或
    多播委托
  • 一种类型不能继承另一种类型
  • 所有这些规则都适用于可隐式转换为参数类型的任何类型
  • 这两种类型都必须是密封的,或者必须是值类型
(这些规则中的一些可以在呼叫站点强制执行)

在实践中,这样的特性会有很多限制,几乎一文不值

因此,此功能将被禁用


它还将创造一个全新的突破性变化类别。解封类型、添加隐式转换或其他看似琐碎的事情现在可能会破坏客户机代码。

如果“最后一个参数”的长度可变,则第二个/第三个/n参数将不是必需的,因为根据您的示例,它将包含在第一个参数中,并且是模糊的:

T f(params A[] a, params B[] b)
b将包含在a中

void DoSomething( params object[] p1, params int[] p2 )
{
...   
} 

 DoSomething( 1, 2, 3 );
想想编译器是否能解决这个问题。你能给“…”部分编码吗?如果是,它是否可读


<>我可以告诉你:这将是一个烂摊子。< /p>如何确定代码> > <代码>结束,<代码> b>代码>开始?C++中的方法相同,我相信C。我会认为这是很明显的,就像zerkms说的那样…@zerkms:当完成
A
类型的元素并开始
B
类型的元素时。@Tom:这并不像你想的那么明显:“太复杂”是一种轻描淡写的说法;在许多情况下,这是不可能的(即,当隐式转换被允许)。即使C++,DoGy句法结构的国王,也不允许这样。这不是不可能的。它只会有很多
No
s。因此在我的评论中谨慎地使用了“许多情况”:@EdS:我以为你的意思是不可能编写规则。继承使这变得复杂的唯一原因是因为CLR类型系统的一个根本性故障,它的设计者承认这是一个错误,如果T1从T2继承,则将
数组
转换为
数组
。在一致类型系统中,这根本不是问题。更不用说所有重载解析等都发生在编译时。@DeadMG:就我个人而言,我认为系统是有意义的-它允许
Array
像任何其他类一样运行,而不允许特殊的行为。即使如此,这也不会真正改变编译器识别两个
参数数组的方式。如果我是OP,我会回答编译器不会编译这样不明显的情况,而是编译了一些更确定的情况,比如
参数int[]a,参数string[]b
;-)@泽克:是的。然而,这些规则将极其复杂。请看我的答案。@zerkms:您还必须避免从一种类型隐式转换到另一种类型的情况。太复杂,不太有用,无法证明该功能的合理性。