danilshik Asked:2020-03-22 04:37:42 +0000 UTC2020-03-22 04:37:42 +0000 UTC 2020-03-22 04:37:42 +0000 UTC C#中输入变量的可变数量 772 今天去面试,问题之一是: 如何将可变数量的变量传递给方法? 第一个想法是使用数组。但是,不幸的是,有人澄清说没有提供数组的使用。 不幸的是,除了使用列表和数组之外,我什么都没想到。有兴趣了解选项。 问题是在 C# 的上下文中。 PS我写道:“实现方法重载”。 c# 3 个回答 Voted Best Answer user176262 2020-03-22T04:39:00Z2020-03-22T04:39:00Z 关键字params- void MyMethod(params object[] inputs) { } 称呼 MyMethod(1, "dva", 3.0, false); https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/params Kir_Antipov 2020-03-22T10:41:03Z2020-03-22T10:41:03Z 更不用说这是一种罪过__arglist! 考虑代码: public static decimal Sum(__arglist) { ArgIterator i = new ArgIterator(__arglist); decimal result = 0; while (i.GetRemainingCount() > 0) result += (decimal)Convert.ChangeType(TypedReference.ToObject(i.GetNextArg()), typeof(decimal)); return result; } ... Console.WriteLine(Sum(__arglist(-1, 12L, 4U, 0.25, 0.25m, 30UL))); // 45.5 这使用了未记录的C# 功能 事实是,IL我们的 C# 编译成的,支持vararg-convention(即,您可以创建具有动态数量参数的函数,其值在调用时将从顶部获取堆栈。这不适合你params,将所有传递到数组中的东西打包) 我不建议你使用这个权利:通常打包成一个数组要快很多倍!那么,为什么要添加这个功能C#呢?事实是,多亏了这一点,您可以轻松地与本地库中的变量函数进行交互: [DllImport("foo.dll", CallingConvention = CallingConvention.Cdecl] static extern int Foo(__arglist); // Нативная функция с переменным числом парметров 我们来看看IL下面的代码: public static decimal SumParams(params object[] Objects) => Objects.Aggregate(0m, (sum, i) => sum + (decimal)Convert.ChangeType(i, typeof(decimal))); public static decimal SumVarargs(__arglist) { ArgIterator i = new ArgIterator(__arglist); decimal result = 0; while (i.GetRemainingCount() > 0) result += (decimal)Convert.ChangeType(TypedReference.ToObject(i.GetNextArg()), typeof(decimal)); return result; } ... SumParams(-1, 12L); SumVarargs(__arglist(-1, 12L)); 签名SumParams: .method public hidebysig static valuetype [mscorlib]System.Decimal SumParams(object[]) cil managed // object[] -> decimal 挑战SumParams: ldc.i4.2 newarr [mscorlib]System.Object // new object[2] a dup ldc.i4.0 ldc.i4.m1 box [mscorlib]System.Int32 stelem.ref // a[0] = (object)(-1) dup ldc.i4.1 ldc.i4.s 12 conv.i8 box [mscorlib]System.Int64 stelem.ref // a[1] = (object)((long)12) call valuetype [mscorlib]System.Decimal Program::SumParams(object[]) // сам вызов 现在签名SumVarargs: .method public hidebysig static vararg valuetype [mscorlib]System.Decimal SumVarargs() cil managed // () -> decimal 如您所见,该方法根本没有参数!只有关键字vararg可以帮助我们理解这是一个变量函数。 挑战SumVarargs: ldc.i4.m1 // -1 ldc.i4.s 12 conv.i8 // (long)12 call vararg valuetype [mscorlib]System.Decimal Program::SumVarargs(..., int32, int64) // сам вызов 很容易看出,这段代码没有打包到数组中。对象被压入堆栈,并调用该方法,就好像它的签名是这样的(int, long) -> decimal:但实际上,标明参数的类型只是为了了解从堆栈中取什么以及取多少) rdorn 2020-03-22T20:57:15Z2020-03-22T20:57:15Z 另一种选择是将所有东西都放在一个地方。 如果您需要来自固定列表的可变数量的参数,您可以通过使用参数的默认值并在调用时对其进行命名访问而无需重载。 例如: void ExampleMethod(int a = 0, double b = 0.0, string c = ""){} 处理: //без именования параметров порядок при обращении важен //Так можно ExampleMethod(10); ExampleMethod(10, 3.3); ExampleMethod(10, 3.3, ""); //Так нельзя ExampleMethod(3.3, ""); //При именованном обращении порядок не важен ExampleMethod(a:10, b:3.3, c:""); ExampleMethod(b:3.3, a:10, c:""); ExampleMethod(c:"", a:10); ExampleMethod(b:3.3);
关键字
params-称呼
https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/params
更不用说这是一种罪过
__arglist!考虑代码:
这使用了未记录的C# 功能
事实是,
IL我们的 C# 编译成的,支持vararg-convention(即,您可以创建具有动态数量参数的函数,其值在调用时将从顶部获取堆栈。这不适合你params,将所有传递到数组中的东西打包)我不建议你使用这个权利:通常打包成一个数组要快很多倍!那么,为什么要添加这个功能
C#呢?事实是,多亏了这一点,您可以轻松地与本地库中的变量函数进行交互:我们来看看
IL下面的代码:签名
SumParams:挑战
SumParams:现在签名
SumVarargs:如您所见,该方法根本没有参数!只有关键字
vararg可以帮助我们理解这是一个变量函数。挑战
SumVarargs:很容易看出,这段代码没有打包到数组中。对象被压入堆栈,并调用该方法,就好像它的签名是这样的
(int, long) -> decimal:但实际上,标明参数的类型只是为了了解从堆栈中取什么以及取多少)另一种选择是将所有东西都放在一个地方。
如果您需要来自固定列表的可变数量的参数,您可以通过使用参数的默认值并在调用时对其进行命名访问而无需重载。
例如:
处理: