c# - 在 .NET 中,使用 "foreach"迭代 IEnumerable<ValueType> 的实例会创建副本吗?那么我应该更喜欢使用 "for"而不是 "foreach"吗?

标签 c# .net performance foreach value-type

在 .NET 中,使用“foreach”迭代 IEnumerable 的实例会创建副本吗?那么我应该更喜欢使用“for”而不是“foreach”吗?

我写了一些代码来证明这一点:

struct ValueTypeWithOneField
{
    private Int64 field1;
}

struct ValueTypeWithFiveField
{
    private Int64 field1;
    private Int64 field2;
    private Int64 field3;
    private Int64 field4;
    private Int64 field5;
}

public class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine("one field");
        Test<ValueTypeWithOneField>();

        Console.WriteLine("-----------");

        Console.WriteLine("Five field");
        Test<ValueTypeWithFiveField>();

        Console.ReadLine();
    }

    static void Test<T>()
    {
        var test = new List<T>();
        for (int i = 0; i < 5000000; i++)
        {
            test.Add(default(T));
        }

        Stopwatch sw = new Stopwatch();

        for (int i = 0; i < 5; i++)
        {
            sw.Start();

            foreach (var item in test)
            {

            }

            sw.Stop();
            Console.WriteLine("foreach " + sw.ElapsedMilliseconds);
            sw.Restart();

            for (int j = 0; j < test.Count; j++)
            {
                T temp = test[j];
            }

            sw.Stop();
            Console.WriteLine("for " + sw.ElapsedMilliseconds);
            sw.Reset();
        }
    }}

这是我运行代码后得到的结果:

    one field
    foreach 68
    for 72
    foreach 68
    for 72
    foreach 67
    for 72
    foreach 64
    for 73
    foreach 68
    for 72
    -----------
    Five field
    foreach 272
    for 193
    foreach 273
    for 191
    foreach 272
    for 190
    foreach 271
    for 190
    foreach 275
    for 188

正如我们在结果中看到的,“foreach”总是比“for”花费更多的时间。

那么在遍历值类型的通用集合时,我应该更喜欢使用“for”而不是“foreach”吗?

注意:感谢提醒,我修改了代码和结果。但是,foreach 的运行速度仍然比 for 慢。

最佳答案

您的问题太复杂了。分解它。

Does using “foreach” to iterate a sequence of value types create a copy of the sequence?

没有。

Does using "foreach" to iterate a sequence of value types create a copy of each value?

是的。

Does using "for" to do an equivalent iteration of an indexed sequence of value types create a copy of each value?

通常,是的。如果您知道集合的特殊情况,例如它是一个数组,您可以采取一些措施来避免复制。但在索引集合的一般情况下,索引序列会返回序列中值的副本,而不是对包含该值的存储位置的引用

Does doing anything to a value type make a copy of the value?

刚好。值类型按值复制。这就是它们被称为值类型的原因。您对不制作副本的值类型所做的唯一事情是调用值类型的方法,并使用“out”或“ref”传递值类型变量。值类型被不断地复制;这就是为什么值类型通常比引用类型慢。

Does using "foreach" or "for" to iterate a sequence of reference type copy the reference?

是的。引用类型的表达式的值是一个引用。无论何时使用该引用都会被复制。

So what's the difference between value types and reference types as far as their copying behaviour is concerned?

值类型按值复制。引用类型复制引用而不是被引用的东西。每次使用 16 字节的值类型都会复制 16 个字节。每次使用 16 字节引用类型时都会复制 4(或 8)字节引用。

Is the foreach loop slower than the for loop?

通常是这样。 foreach 循环通常做更多的工作,因为它创建一个枚举器并调用枚举器上的方法,而不是仅仅递增一个整数。整数增量非常快。另外不要忘记必须释放 foreach 循环中的枚举器,这也需要时间。

Should I use the for loop instead of the foreach loop because the for loop is sometimes a few microseconds faster?

没有。那是愚蠢的。您应该根据以客户为中心的经验数据做出明智的工程决策。 foreach 循环的额外负担很小。客户可能永远不会注意到。你应该做的是:

  • 根据客户意见设定绩效目标
  • 衡量您是否达到了目标
  • 如果没有,使用分析器找到最慢的东西
  • 修复它
  • 重复,直到你达到你的目标

如果您遇到性能问题,那么将 foreach 循环更改为 for 循环对您的问题没有任何影响。首先按照看起来清晰易懂的方式编写代码。

关于c# - 在 .NET 中,使用 "foreach"迭代 IEnumerable<ValueType> 的实例会创建副本吗?那么我应该更喜欢使用 "for"而不是 "foreach"吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5663783/

相关文章:

c# - 在步骤 C# 中将用户输入添加到数组?

c# - 在 SSH 隧道中创建转发端口

c# - 使用 ReferenceEquals 的 IEqualityComparer<T>

c# - 如何确定窗体上的哪个控件具有焦点?

sql-server - SSRS sql 查询运行缓慢

perl - 关于在 Perl 中正确使用取消引用的困惑

java - 存储与保存生成字符串

c# - 温莎 Ioc 服务覆盖 : There is a component already registered for the given key

c# - 无法加载文件或程序集。无效指针(HRESULT : 0x80004003 (E_POINTER)) 异常

c# - 从 Access 2003 调用托管代码