并行扩展:帮助我理解 LazyInit

发布于 2024-07-08 20:58:20 字数 1291 浏览 10 评论 0原文

面向未来读者的更新:当 .NET 4 发布时,CTP 中的 LazyInit 将重命名为 Lazy 并且将从结构更改为类,因此很少适用,除非作为说明为什么如果不小心可变结构可能会出现问题。

我一直在 Parallel Extensions June CTP 中尝试使用 LazyInit,我希望以下代码能够打印出相同的 Guid 一千次,但实际上却打印出一千次不同的 Guid。 显然,我在这里遗漏了一些关于 LazyInit 应该如何工作的明显内容,如果有人能指出它是什么,我将不胜感激。

using System;
using System.Diagnostics;
using System.Threading;

namespace TestApp
{
    class Program
    {
        static void Main(string[] args)
        {
            for (int i=0; i < 1000; i++)
            {
                Console.WriteLine(TestClass.Instance.Id);
            }

            Console.Write("Press any key to continue:");
            Console.ReadKey();
        }

        private class TestClass
        {
            private static readonly LazyInit<TestClass> _instance = new LazyInit<TestClass>(() => new TestClass(), LazyInitMode.EnsureSingleExecution);

            public static TestClass Instance
            {
                get { return _instance.Value; }
            }

            private TestClass()
            {
                Debug.WriteLine("TestClass Constructor");
                Id = Guid.NewGuid();
            }

            public Guid Id { get; private set; }
        }
    }
}

Update for future readers: When .NET 4 comes out, LazyInit<T> from the CTP will have been renamed to Lazy<T> and will be changed from a struct to a class, so very little of this will apply, except as an illustration of why mutable structs can be problematic if you're not careful.

I've been experimenting with LazyInit in the Parallel Extensions June CTP, and I would expect the following code to print out the same Guid a thousand times, but instead it prints out a thousand different Guids. Clearly I'm missing something obvious here about how LazyInit is supposed to work, and I'd appreciate if someone would kindly point out what it is.

using System;
using System.Diagnostics;
using System.Threading;

namespace TestApp
{
    class Program
    {
        static void Main(string[] args)
        {
            for (int i=0; i < 1000; i++)
            {
                Console.WriteLine(TestClass.Instance.Id);
            }

            Console.Write("Press any key to continue:");
            Console.ReadKey();
        }

        private class TestClass
        {
            private static readonly LazyInit<TestClass> _instance = new LazyInit<TestClass>(() => new TestClass(), LazyInitMode.EnsureSingleExecution);

            public static TestClass Instance
            {
                get { return _instance.Value; }
            }

            private TestClass()
            {
                Debug.WriteLine("TestClass Constructor");
                Id = Guid.NewGuid();
            }

            public Guid Id { get; private set; }
        }
    }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

森林很绿却致人迷途 2024-07-15 20:58:20

简短版本:将静态设置为非只读,它将修复您遇到的错误。

长版本:这是 C# 中非常容易被误解的部分。 当您访问一个结构体时,您正在访问该结构体的副本。 LazyInit.Value 的底层调用是一个变异操作。 通常会执行回拷,但在只读字段的情况下,无法执行回拷,因此仍然保留未初始化的值。

非常详细的解释: http://ericlippert.com/2008/05/14 /mutating-readonly-structs/

Short Version: Make the static non-readonly and it will fix the bug you are experiencing.

Long Version: This is a very misunderstood portion of C#. When you access a struct you are accessing a copy of the struct. The underlying call of LazyInit.Value is a mutating operation. Normally a copyback is performed but in the case of a read-only field there is no way to perform the copy back and hence you are still left with an uninitialized value.

Extremely detailed explanation: http://ericlippert.com/2008/05/14/mutating-readonly-structs/

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文