【问题标题】:JavaScript spread syntax in C#C# 中的 JavaScript 扩展语法
【发布时间】:2017-02-14 15:36:18
【问题描述】:

在 C# 中有没有像 JavaScript's spread syntax 这样的实现?

var arr = new []{
   "1",
   "2"//...
};

Console.WriteLine(...arr);

【问题讨论】:

  • 将数组传递给params 是您将要获得的最接近的方法。
  • 参数中带有关键字params 的方法更可能是答案。谢谢@Rob
  • @KeithNicholas 我认为这在其他情况下确实有意义,例如ctx.users.Select(u => new { u.id, u.otherfields } ).ToList().ConvertAll(u => new { ...u, someList.FirstOrDefault(l => l.userid == u.id).something})
  • 小挑剔,... 语法是 not 运算符。在规范中,它在语言语法中被称为SpreadElement,尽管非正式地称为“扩展语法”,因为它不是上下文无关语法。
  • (a, b, ...others) = getTwoParamsAndOthersIntoArray() - 不知道为什么这种语法在 C# 中不会比 JS 更有意义,因为它现在具有动态、值元组和解构 :)

标签: javascript c# spread-syntax


【解决方案1】:

没有传播选项。而且是有原因的。

  1. 除非您使用 params 关键字,否则属性不是 C# 中的数组
  2. 使用 param 关键字的属性必须:
    1. 共享同类型
    2. 具有可转换的共享类型,例如数字的双精度数
    3. 属于 object[] 类型(因为 object 是一切的根类型)

不过,话虽如此,您可以通过各种语言功能获得类似的功能。

回答你的例子:

C#

var arr = new []{
   "1",
   "2"//...
};

Console.WriteLine(string.Join(", ", arr));

您提供的链接有这个例子:

Javascript 传播

function sum(x, y, z) {
  return x + y + z;
}

const numbers = [1, 2, 3];

console.log(sum(...numbers));
// expected output: 6

console.log(sum.apply(null, numbers));

参数 在 C# 中,具有相同的类型

public int Sum(params int[] values)
{
     return values.Sum(); // Using linq here shows part of why this doesn't make sense.
}

var numbers = new int[] {1,2,3};

Console.WriteLine(Sum(numbers));

在 C# 中,具有不同的数字类型,使用双精度

public int Sum(params double[] values)
{
     return values.Sum(); // Using linq here shows part of why this doesn't make sense.
}

var numbers = new double[] {1.5, 2.0, 3.0}; // Double usually doesn't have precision issues with small whole numbers

Console.WriteLine(Sum(numbers));

反思 在 C# 中,使用不同的数字类型,使用对象和反射,这可能最接近您的要求。

using System;
using System.Reflection;

namespace ReflectionExample
{
    class Program
    {
        static void Main(string[] args)
        {
            var paramSet = new object[] { 1, 2.0, 3L };
            var mi = typeof(Program).GetMethod("Sum", BindingFlags.Public | BindingFlags.Static);
            Console.WriteLine(mi.Invoke(null, paramSet));
        }

        public static int Sum(int x, double y, long z)
        {
            return x + (int)y + (int)z;
        }
    }
}

【讨论】:

  • 您的反射示例实际上更类似于 JavaScript 的 Function.prototype.apply(),这是一个很棒的 pre-ES6 功能,在传播语法可用之前已经使用了很多,但无论如何都是很好的建议(尽管我不会在性能关键的生产代码中推荐它)。
【解决方案2】:

获得与此类似的行为(无需反射)的一个技巧是接受params SomeObject[][],并定义一个从SomeObjectSomeObject[] 的隐式运算符。现在您可以传递SomeObject 和单个SomeObject 元素的混合数组。

public class Item
{
    public string Text { get; }

    public Item (string text)
    {
        this.Text = text;
    }

    public static implicit operator Item[] (Item one) => new[] { one };
}

public class Print
{
    // Accept a params of arrays of items (but also single items because of implicit cast)

    public static void WriteLine(params Item[][] items)
    {
        Console.WriteLine(string.Join(", ", items.SelectMany(x => x)));
    }
}

public class Test
{
    public void Main()
    {
        var array = new[] { new Item("a1"), new Item("a2"), new Item("a3") };
        Print.WriteLine(new Item("one"), /* ... */ array, new Item("two")); 
    }
}

【讨论】:

    【解决方案3】:

    C# 中没有直接的预构建库来处理 Spread 中内置的内容

    为了在 C# 中获得该功能,您需要反射对象并通过其访问修饰符获取方法、属性或字段。

    你会做这样的事情:

    var tempMethods = typeof(myClass).GetMethods();
    var tempFields = typeof(myClass).GetFields();
    var tempProperties = typeof(myClass).GetProperties();
    

    然后遍历并将它们放入您的动态对象中:

    using System;
    using System.Collections.Generic;
    using System.Dynamic;
    
    namespace myApp
    {
        public class myClass
        {
            public string myProp { get; set; }
            public string myField;
            public string myFunction()
            {
                return "";
            }
        }
    
        class Program
        {
            static void Main(string[] args)
            {
                var fields = typeof(myClass).GetFields();
                dynamic EO = new ExpandoObject();
                foreach (int i = 0; i < fields.Length; i++)
                {
                    AddProperty(EO, "Language", "lang" + i);
                    Console.Write(EO.Language);
                }
            }
    
            public static void AddProperty(ExpandoObject expando, string propertyName, object propertyValue)
            {
                // ExpandoObject supports IDictionary so we can extend it like this
                var expandoDict = expando as IDictionary<string, object>;
                if (expandoDict.ContainsKey(propertyName))
                    expandoDict[propertyName] = propertyValue;
                else
                    expandoDict.Add(propertyName, propertyValue);
            }
        }
    } 
    

    https://www.oreilly.com/learning/building-c-objects-dynamically

    【讨论】:

      【解决方案4】:

      你也可以这样做

          var a  = new List<int>(new int[]{1,2,3}){5};
          Console.WriteLine(a.Count);
      

      将打印 4

      如果你想用附带的可枚举和参数来实现列表或数组的初始化

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-07-30
        • 2023-01-10
        • 1970-01-01
        • 1970-01-01
        • 2014-01-15
        • 2023-01-28
        相关资源
        最近更新 更多