2011-03-06 85 views
4

我喜欢能够为可以使用的类提供默认值,但问题是如果它们被更改,那么它将影响对它的所有引用并且不会是“默认”。通过使用像这样的默认值,它可以节省内存,并允许默认值(如果需要)传播到所有使用默认值的引用。静态不可变的默认实例

一个简单的例子是

class A 
{ 
    static public A Default; 
} 

然后可以使用A.Default作为A的“默认”的实例同样,问题是,A是不是一成不变的或者至少是“冻结”并变为它会改变所有的参考。如果这是人们想要的行为,这可能很好,但如果默认情况下发生了意外更改,可能会造成严重破坏。

我真正需要的是一种深度冻结和解冻Default的方法。

很明显,一种方法是简单地让所有setter只在一个条件上设置并将collection标记为只读。提供这样简单的行为似乎有很多重复的工作。

有没有一个简单的库,模式或反射来完成这个?写入时复制能力会很好,所以如果试图改变Default,就会创建一个新的可变实例。不仅如此,即使flyweight实例可以创建,如果它有机会提高性能(更改的大小)。

示例:假设您最初创建1M个具有所有相同状态的大(内存大小)对象。通过使用默认模式,这只会创建1个实际的对象。假设你改变了所有状态的1个参数(比如位置),但对象本身非常大。使用flyweight模式,您只需1M个已更改的参数即可跟踪(较慢但内存较少),而不是1M个新对象。在改变了足够的参数之后,完整的对象最终被分配给它的引用。

这里有什么吗?

+1

在什么情况下,你会想“解冻”默认与谁应该可以“解冻”默认? – shahkalpesh 2011-03-06 15:56:33

+0

你确定你确实需要这个复杂的东西吗? – 2011-03-06 16:00:57

+0

这似乎是一个设计缺陷。你有一个类A,当它的“Default”实例不可变时,它是不可变的。Perhapes你需要两个类,一个不可变和可变的,或者让你的类A成为一个结构体或值类型,比如object(即像String) – MerickOWA 2011-03-06 16:15:25

回答

0

没有什么像现成的盒子可用。您需要创建自己的写时拷贝实例和代码。

旅游真正写入时复制行为做:

  • 创建一个小的“参照”对象,每一次有人读了“Default”属性返回它的一个新的实例。这个对象总是引用相同的(私有的,按定义只读)内部数据。

  • 无论何时数据发生变化,并且您仍在只读数据上,请创建内部数据的副本并将其分配给您的参考对象。

.NET Framework设计人员为一些类似需求的类采用了更明确的路由。例如,如果您看到CultureInfo,“默认”实例是只读的,并且如果您尝试修改这些,则会发生异常。但是,您可以轻松创建可变副本(其中一个构造函数接受另一个CultureInfo实例)。

+0

是的,但我不知道如何在一般和有效的情况下完成这样的事情。一个案件​​并不难,但如果你必须一直这样做,那就是一团糟。他们是如何实现其只读默认值的?看他们说的帮助,他们使用了一个包装,但是这个包装完成了很长的路还是什么? – AbstractDissonance 2011-03-06 16:33:26

+0

如果你必须一直这么做,那么你的设计可能会出错。关于MS和'CultureInfo'等,从我可以告诉他们明确实现了包装。无论如何,总是有可能使用代码生成工具,它使用模板生成样板代码,这样基本上只会编写一次模板,然后生成代码。或者,您可以使用抽象类或接口,并在运行时用Reflection.Emit来生成代码......有很多可能性。 – Lucero 2011-03-07 00:40:40

0

有几个方法可以做到这一点,映入脑海:

  1. 有一个名为IsReadOnly标志,使得所有的存取器(即可以改变一个实例的setter和方法)抛出一个异常时,这是真的。将使用IsReadOnly设置为true来创建您的Default实例。

  2. 创建一个基类(FooReadOnly),其中所有的增变器都会抛出异常,然后创建增效器工作的派生类(Foo)。您的Default实例的类型为FooReadOnly

0

您可能会了解DependancyObject(s)和DependanceProperty如何在WPF/Silverlight中工作。

下面是它在WPF/Silverlight中是如何工作的一类“A”与属性“富”与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是对象,他们可以持有可通过尚未overrided价值的任何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的实例的任何方法不使用默认值,除非明确规定是这么说的。