c# - 有没有办法调用需要 IEnumerable<T> 与单个值的 C# 方法? ...与基准测试

标签 c# collections ienumerable

这个问题在这里已经有了答案:





Passing a single item as IEnumerable<T>

(20 个回答)


去年关闭。




我只是想知道我是否错过了一些语法糖或微优化......
如果我正在调用一个需要 IEnumerable 值的方法,但我只有一个值,那么我将该单个值放在一个数组中。
例如:

var x = 1.23;
SquareAllTheNumbers(new[] { x });


private void SquareAllTheNumbers(IEnumerable<double> values)
{
    foreach (var value in values)
    {
        Console.WriteLine(Math.Sqrt(value));
    }
}

即使不需要,这也需要一个来制作一个数组。看起来我应该能够写出类似的东西:
var x = 1.23;
SquareAllTheNumbers(yield x);

有没有办法在不创建数组的情况下调用函数?

[编辑]
感谢您的快速回复。所以,我了解到,正如下面和过去的相同问题( Passing a single item as IEnumerable<T> )所指出的,有四种解决方案。我肯定喜欢额外的 yield 方法,并且不需要生成新数组,但它更好吗?嗯,我一直想更多地了解 Benchmark.NET,所以我决定测试这四个想法。这些是:
  • 创建一个数组 ( new[] { x } )
  • 产量方法
  • 可枚举。重复
  • 参数双[]

  • 这些可以在下面的代码中更好地理解:
            [Benchmark(Description = "Array Approach")]
            public double ArrayApproach()
            {
                var x = 1.23;
                return SumOfSquaredNumbers(new[] { x });
            }
    
            [Benchmark(Description = "Yield Method Approach")]
            public double YieldMethodApproach()
            {
                return SumOfSquaredNumbers(Yield(x));
            }
    
            [Benchmark(Description = "Enumerable Repeat Approach")]
            public double RepeatMethodApproach()
            {
                return SumOfSquaredNumbers(Enumerable.Repeat(x, 1));
            }
            [Benchmark(Description = "Params Approach")]
            public double ParamsApproach()
            {
                return SumOfSquaredNumbers(x);
            }
    
            private double SumOfSquaredNumbers(IEnumerable<double> values)
            {
                var result = 0.0;
                foreach (var value in values)
                {
                    result = value * value;
                }
    
                return result;
            }
            private double SumOfSquaredNumbers(params double[] values)
            {
                var result = 0.0;
                foreach (var value in values)
                {
                    result = value * value;
                }
    
                return result;
            }
    
            public IEnumerable<T> Yield<T>(T item)
            {
                yield return item;
            }
    

    这是基准测试的结果:
    |                       Method |      Mean |      Error |    StdDev |  Gen 0 | Allocated |
    |----------------------------- |----------:|-----------:|----------:|-------:|----------:|
    |             'Array Approach' |  6.970 ns | 10.7471 ns | 0.5891 ns | 0.0076 |      32 B |
    |      'Yield Method Approach' | 30.256 ns | 21.7358 ns | 1.1914 ns | 0.0114 |      48 B |
    | 'Enumerable Repeat Approach' | 30.058 ns | 32.9930 ns | 1.8085 ns | 0.0095 |      40 B |
    |            'Params Approach' |  5.330 ns |  0.6169 ns | 0.0338 ns | 0.0077 |      32 B |
    

    因此,看起来最好的方法是创建一个新数组。第四个选项(使用 params double[] )表现良好,但有点超出问题范围,因为我的意思是该方法是“一成不变的”——例如,3rd 方 DLL 的一部分。

    最佳答案

    数组是 IEnumerable 的具体实现,所以我认为创建一个传递值没有错。

    如果您追求语法糖,则 params 可能会导致过载。参数,这意味着编译器将为您创建一个数组:

    private static void SquareAllTheNumbers(params double[] values) {
        foreach (var value in values) {
            Console.WriteLine(Math.Sqrt(value));
        }
    }
    
    static void Main(string[] args) {
        SquareAllTheNumbers(2);
        SquareAllTheNumbers(1,2,3);
    }
    

    关于c# - 有没有办法调用需要 IEnumerable<T> 与单个值的 C# 方法? ...与基准测试,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62296111/

    相关文章:

    c# - (C# 7.2) "private protected"修饰符的用例是什么?

    c# - EF 与 Nhibernate 合并断开连接的对象图

    c# - 如何将验证属性应用于集合中的对象?

    c# - 将标志转换为 IEnumerable<Enum> 的扩展方法,反之 (C#)

    c# - 如何将 IEnumerable<T> 添加到现有的 ICollection<T>

    c# - 添加逗号的字符串格式,如果非零则仅显示两位小数

    c# - 获取 Windows 版本

    java - 什么时候在Java中通过ArrayList使用LinkedList?

    java - 如何在删除对象之前清除集合

    c# - 如何将 IEnumerable(无类型)转换为 IQueryable<T>?