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

本文关键字:参数 许一个 方法 最后一个 为什么 | 更新日期: 2023-09-27 17:59:05

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

T f(A a, params B[] b)允许如果你有A r; .... B x, y, z; ....,你可以像f (r, x, y, z)一样调用f。为什么C#没有定义类似的东西:

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

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

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

请告诉我argOneargTwo应该在方法体内部包含什么:

void Foo( params object[] argOne, params object[] argTwo )
{
    // whatever
} 
Foo( 1, false, "Hello", new object(), 2.3 );

因为确定何时允许这样的构造太复杂了
(呼叫明确时)
尽管制定一套好的规则是可能的,但它们会相当复杂,难以理解。人们最终会问,如果案例X有微妙的歧义,为什么它不起作用。

例如:

  • 两种类型都不能是接口或泛型参数
  • 如果一种类型是枚举或数字类型,则另一种类型必须是objectEnum以外的类
  • 如果一种类型是委托,则另一种类型不能也是委托类型(也不能是objectDelegateMulticastDelegate
  • 一种类型不能继承另一种类型
  • 所有这些规则都适用于任何可隐式转换为参数类型的类型
  • 两种类型都必须是sealed或必须是值类型

(其中一些规则可以在呼叫站点强制执行)

在实践中,这样的功能会有太多的限制,几乎毫无价值。

因此,此功能将从-10000点开始。

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

因为歧义。如果你去做了:

T f(params int[] a, params int[] b)

你打电话给

f(1, 2, 3, 4)

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

(另一个例子:

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

string继承自object。这仍然是模棱两可的…)

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

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", "?");

该示例显示了如何无法知道第一个params[]在哪里结束,下一个params[]在哪里开始。

这会引发问题并导致冲突。

例如,假设B继承自A

编译器如何理解:

f(A1, A2, B1, B2)

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

我认为理论上编译器可以是聪明的,可以检测冲突
然而,最初在设计.NET和C#时,其想法是尽量避免出现这种明确而棘手的情况。

void DoSomething( params object[] p1, params int[] p2 )
{
...   
} 
 DoSomething( 1, 2, 3 );

想想编译器是否能解决这个问题。你能给"…"编码吗部分如果是,它是否可读?

我可以告诉你:这将是一个混乱

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

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

b将包含在中