并行扩展:帮助我理解 LazyInit
面向未来读者的更新:当 .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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
简短版本:将静态设置为非只读,它将修复您遇到的错误。
长版本:这是 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/