2011-03-06 3 views
4

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

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

class A 
{ 
    static public A Default; 
} 

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

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

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

Есть ли простая библиотека, узор или отражение, чтобы выполнить это? Возможность копирования на запись была бы приятной, так что, если попытка по умолчанию будет изменена, будет создан новый изменяемый экземпляр. Мало того, даже экземпляр мухи может быть создан, если у него есть шанс увеличить производительность (размер изменений).

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

Что-нибудь там вроде этого?

+1

В каком состоянии вы хотите «разморозить» по умолчанию и кто должен «разморозить» значение по умолчанию? – shahkalpesh

+0

Вы уверены, что вам действительно нужен что-то такое сложное? –

+0

Это похоже на дефект дизайна. У вас есть класс A, который является неизменным, когда его экземпляр «Default» еще изменен, когда его нет.В Perhapes вам нужно, чтобы два класса были неизменяемыми и изменяемыми, или perhapes ваш класс A действительно должен быть объектом типа struct или типа значения (например, String). – MerickOWA

ответ

0

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

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

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

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

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

+0

Да, но я не уверен, как это сделать в целом и эффективно. Нетрудно сделать это для одного случая, но это беспорядок, если вам нужно делать это все время. Как они реализовали свои стандартные значения по умолчанию? Глядя на помощь, она говорит, что они использовали обертку, но была ли эта обертка длинным или что? – AbstractDissonance

+0

Если вам нужно делать это все время, тогда ваш дизайн может как-то ошибиться. Что касается MS и 'CultureInfo' и т. Д., Я могу сказать, что они явно реализовали оболочки. В любом случае, всегда есть возможность использовать инструмент генерации кода, который использует шаблоны для генерации кода шаблона, так что вы в основном только пишете шаблон один раз, а затем генерируете код вокруг него. Или вы можете использовать абстрактные классы или интерфейсы и генерировать код во время выполнения с помощью 'Reflection.Emit' ... есть много возможностей. – Lucero

0

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

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

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

0

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

Вот пример того, как это работает в WPF/Silverlight для класса «А» со свойством «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, его легко реализовать в одном месте логику для того, чтобы сделать определенные свойства или целые объекты только для чтения.

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

2

Один из возможных способов я использую для реализации интерфейса только для чтения и изменить статический тип по умолчанию вернуться к этому:

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 не используется по умолчанию, если это явно не говорит об этом.

Смежные вопросы