Параллельные расширения: помогите мне понять LazyInit <T> - PullRequest
3 голосов
/ 11 ноября 2008

Обновление для будущих читателей: Когда выйдет .NET 4, LazyInit<T> из CTP будет переименован в Lazy<T> и будет изменен со структуры на класс, поэтому очень мало это применимо, за исключением иллюстрации того, почему изменчивые структуры могут быть проблематичными, если вы не будете осторожны.

Я экспериментировал с LazyInit в июньской CTP-версии Parallel Extensions, и я ожидал, что следующий код будет распечатывать один и тот же 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; }
        }
    }
}

1 Ответ

12 голосов
/ 11 ноября 2008

Короткая версия: Сделайте статическую не доступной только для чтения, и это исправит ошибку, с которой вы столкнулись.

Длинная версия: Это очень неправильно понятая часть C #. Когда вы получаете доступ к структуре, вы получаете доступ к копии структуры. Основной вызов LazyInit.Value - это мутирующая операция. Обычно выполняется обратное копирование, но в случае поля только для чтения невозможно выполнить обратное копирование, и, следовательно, у вас все еще остается неинициализированное значение.

Очень подробное объяснение: http://ericlippert.com/2008/05/14/mutating-readonly-structs/

...