RError.com

RError.com Logo RError.com Logo

RError.com Navigation

  • 主页

Mobile menu

Close
  • 主页
  • 系统&网络
    • 热门问题
    • 最新问题
    • 标签
  • Ubuntu
    • 热门问题
    • 最新问题
    • 标签
  • 帮助
主页 / 问题 / 959724
Accepted
danilshik
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 3 个回答
  • 10 Views

3 个回答

  • Voted
  1. 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

    • 17
  2. 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:但实际上,标明参数的类型只是为了了解从堆栈中取什么以及取多少)

    • 13
  3. 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);
    
    • 2

相关问题

Sidebar

Stats

  • 问题 10021
  • Answers 30001
  • 最佳答案 8000
  • 用户 6900
  • 常问
  • 回答
  • Marko Smith

    根据浏览器窗口的大小调整背景图案的大小

    • 2 个回答
  • Marko Smith

    理解for循环的执行逻辑

    • 1 个回答
  • Marko Smith

    复制动态数组时出错(C++)

    • 1 个回答
  • Marko Smith

    Or and If,elif,else 构造[重复]

    • 1 个回答
  • Marko Smith

    如何构建支持 x64 的 APK

    • 1 个回答
  • Marko Smith

    如何使按钮的输入宽度?

    • 2 个回答
  • Marko Smith

    如何显示对象变量的名称?

    • 3 个回答
  • Marko Smith

    如何循环一个函数?

    • 1 个回答
  • Marko Smith

    LOWORD 宏有什么作用?

    • 2 个回答
  • Marko Smith

    从字符串的开头删除直到并包括一个字符

    • 2 个回答
  • Martin Hope
    Alexandr_TT 2020年新年大赛! 2020-12-20 18:20:21 +0000 UTC
  • Martin Hope
    Alexandr_TT 圣诞树动画 2020-12-23 00:38:08 +0000 UTC
  • Martin Hope
    Air 究竟是什么标识了网站访问者? 2020-11-03 15:49:20 +0000 UTC
  • Martin Hope
    Qwertiy 号码显示 9223372036854775807 2020-07-11 18:16:49 +0000 UTC
  • Martin Hope
    user216109 如何为黑客设下陷阱,或充分击退攻击? 2020-05-10 02:22:52 +0000 UTC
  • Martin Hope
    Qwertiy 并变成3个无穷大 2020-11-06 07:15:57 +0000 UTC
  • Martin Hope
    koks_rs 什么是样板代码? 2020-10-27 15:43:19 +0000 UTC
  • Martin Hope
    Sirop4ik 向 git 提交发布的正确方法是什么? 2020-10-05 00:02:00 +0000 UTC
  • Martin Hope
    faoxis 为什么在这么多示例中函数都称为 foo? 2020-08-15 04:42:49 +0000 UTC
  • Martin Hope
    Pavel Mayorov 如何从事件或回调函数中返回值?或者至少等他们完成。 2020-08-11 16:49:28 +0000 UTC

热门标签

javascript python java php c# c++ html android jquery mysql

Explore

  • 主页
  • 问题
    • 热门问题
    • 最新问题
  • 标签
  • 帮助

Footer

RError.com

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

帮助

© 2023 RError.com All Rights Reserve   沪ICP备12040472号-5