статический неизменяемый экземпляр по умолчанию - PullRequest
4 голосов
/ 06 марта 2011

Мне нравится иметь возможность предоставлять значения по умолчанию для классов, которые можно использовать, но проблема в том, что если они будут изменены, это повлияет на все ссылки на него и не будет "значением по умолчанию".Используя значение по умолчанию, подобное этому, оно экономит память и позволяет распространять значение по умолчанию, если нужно, на все ссылки, которые используют значение по умолчанию.

Простой пример:

class A
{
    static public A Default;
}

Затем можно использовать A.Default в качестве экземпляра A. по умолчанию. Опять же, проблема в том, что A не является неизменным или, по крайней мере, «замороженным», и изменения в нем изменят все ссылки.Это может быть хорошо, если это такое поведение, которое вы хотите, но может вызвать хаос, если значение по умолчанию изменено случайно.

Что мне действительно нужно, так это способ глубокой заморозки и разморозки по умолчанию.

Очевидно, что один из способов - просто установить все сеттеры только на условие и пометить коллекции как доступные только для чтения.Похоже, много повторяющихся работ по обеспечению такого простого поведения.

Существует ли простая библиотека, шаблон или рефлексия для достижения этой цели?Возможность копирования при записи была бы полезна, чтобы при попытке изменить значение Default был создан новый изменяемый экземпляр.Мало того, даже экземпляр flyweight может быть создан, если у него есть шанс повысить производительность (размер изменений).

Пример: Предположим, что вы изначально создаете объекты размером 1 МБ (размер памяти) с одинаковым состоянием.Используя шаблон по умолчанию, это создаст только 1 фактический объект.Предположим, вы изменили 1 параметр для всех состояний (скажем, положение), но сами объекты очень велики.Используя шаблон flyweight, вы бы просто изменили параметры 1M, чтобы отслеживать (медленнее, но меньше памяти, как обычно) вместо 1M новых объектов.После того, как достаточное количество параметров было изменено, полностью выделенному объекту наконец присваивается ссылка.

Что-нибудь подобное?

Ответы [ 4 ]

2 голосов
/ 13 июня 2012

Один из возможных методов, которые я использую, - реализовать интерфейс только для чтения и изменить статический тип возвращаемого значения по умолчанию на:

interface ISomeClass
{
    string MyProperty { get; }
}

class SomeClass : ISomeClass
{
    string MyProperty { get; set; }

    public static ISomeClass Default = new SomeClass(); 
}

Затем вы можете принудительно установить, что в любое время требуются изменения по умолчанию, изменяемая ссылка явно запрашивается, возможно, отдельным методом:

        public static SomeClass GetMutableDefault()
        {
            return Default as SomeClass;
        }

Затем вы получаете проверку во время компиляции, что любой метод, который пытается изменить экземпляр SomeClass, не использует Default, если это явно не указано так.

0 голосов
/ 06 марта 2011

Есть несколько способов сделать это, что приходит на ум:

  1. Имейте флаг с именем IsReadOnly, так что все ваши мутаторы (сеттеры и методы, которые могут изменить экземпляр) выдают исключение, когда оно истинно. Ваш экземпляр Default будет создан с IsReadOnly, установленным в true.

  2. Создайте базовый класс (FooReadOnly), в котором все мутаторы генерируют исключения, затем создайте производный класс (Foo), в котором работают мутаторы. Ваш экземпляр Default будет иметь тип FooReadOnly.

0 голосов
/ 06 марта 2011

Вы можете посмотреть, как DependancyObject (s) и DependanceProperty (s) работают в WPF / Silverlight.

Вот пример того, как это работает в WPF / Silverlight для класса «A» со свойством «Foo» со значением по умолчанию 5.

class A : DependancyObject {
  static DependancyProperty PropertyFoo = DependanceProperty.Register( "Foo", typeof(int), typeof(A), new PropertyMetadata( 5 ) );

  int Foo {
    get { return (int)GetValue( PropertyFoo ); }
    set { SetValue( PropertyFoo, value ); }
  }

Недостатком является то, что вам приходится «вручную» реализовывать ваши свойства, вы не можете воспользоваться простым синтаксисом «int Foo {get; set;}», но фрагменты кода могут помочь совсем немного.

Очевидно, что если вы не хотите использовать WPF или Silverlight, вам придется реализовать все это самостоятельно, но вы получите следующие преимущества.

Поскольку DependancyProperties являются объектами, они могут содержать свое значение по умолчанию, которое может использоваться любым объектом DependancyObject, который не переопределил это значение.

DependancyObjects хранит список значений только в том случае, если значение изменяется, поэтому объекты, совпадающие с объектами по умолчанию, не занимают дополнительной памяти.

Поскольку все наборы свойств проходят через DependancyObject.SetValue, легко реализовать в одном месте логику для создания определенных свойств или целых объектов только для чтения.

Существуют и другие преимущества / функции, которые можно добавить, такие как анимация свойств и т. Д., Но, если вы реализовали это, вы можете сделать его настолько простым / сложным, насколько вам нужно.

0 голосов
/ 06 марта 2011

Ничего подобного из коробки нет в наличии. Вам нужно создать свой собственный экземпляр и код для копирования при записи.

Что нужно сделать для реального копирования при записи:

  • Создайте небольшой «ссылочный» объект, и каждый раз, когда кто-то читает свойство «Default», возвращает его новый экземпляр. Этот объект всегда ссылается на одни и те же (частные, по определению только для чтения) внутренние данные.

  • Всякий раз, когда данные изменяются, а вы все еще находитесь в данных только для чтения, создайте копию внутренних данных и назначьте ее для вашего ссылочного объекта.

Разработчики .NET Framework выбрали более явный путь для некоторых классов с аналогичными требованиями. Например, если вы посмотрите на CultureInfo, экземпляры по умолчанию доступны только для чтения, и если вы попытаетесь изменить их, вы получите исключение. Однако вы можете легко создать изменяемую копию (один из конструкторов принимает другой экземпляр CultureInfo).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...