static immutable default instance
I like to be able to provide default values for classes that can be used but the problem is that if they are changed then it will effect all references to it and won't be "default". By using a default value such as this it saves on memory and does allow the default, if one wants, to propagate to all references that use a default.
A simple example is
class A
{
static public A Default;
}
Then one can use A.Default as a "default" instance of A. Again, the problem is that A is not immutable or at least "frozen" and changes to it will change all references. This can be good if that is the behavior one wants but can cause havoc if the default is changed by accident.
What I really need is a way to deep freeze and unfreeze Default.
Obviously one way is to simply have all the setters set only on a condition and to mark collections as readonly. It seems like a lot of repetitive work to provide such simple behavior.
Is there a simple library, pattern, or reflection to accomplish this? A Copy-on-write ability would be nice to so that if Default is attempted to be changed a new mutable instance would be created. Not only that, even a flyweight instance could be created if it has a chance to increase performance(size of changes).
Example: Suppose you create 1M large(memory size) objects with all the same state initially. By using the default pattern this will only create 1 actual object. Suppose you change 1开发者_如何学Python parameter for all the states(say the position) but the object themselves are very large. Using the flyweight pattern you would just have 1M changed parameters to keep track of(Slower but less memory as usual) instead of 1M new objects. After enough parameters are changed a the full blown object is finally assigned to it's reference.
Anything out there like this?
One possible method I use is to implement a read-only interface and change the static Default return type to that:
interface ISomeClass
{
string MyProperty { get; }
}
class SomeClass : ISomeClass
{
string MyProperty { get; set; }
public static ISomeClass Default = new SomeClass();
}
You can then enforce that any time changes to the Default are required, a mutable reference is explicitly requested, perhaps by separate method:
public static SomeClass GetMutableDefault()
{
return Default as SomeClass;
}
You then get compile-time checking that any method that is attempting to change a SomeClass instance isn't using the Default unless it explicitly says so.
There is nothing like that out of the box available. You need to create your own copy-on-write instance and code.
Things to do for real copy-on-write behavior:
Create a small "reference" object, and each time someone reads the "
Default
" property return a new instance of it. This object always references the same (private, by definition read-only) internal data.Whenever the data is changed and you're still on the read-only data, create a copy of the internal data and assign it to your reference object.
The .NET Framework designers took a more explicit route for some classes with similar requirements. If you look at CultureInfo
for instance, the "default" instances are read-only and if you try to modify those you get an exception. However, you can create a mutable copy easily (one of the constructors accepts another CultureInfo
instance).
There are a couple ways to do this that spring to mind:
Have a flag called
IsReadOnly
, such that all of your mutators (setters and methods that can change an instance) throw an exception when it's true. YourDefault
instance would be created withIsReadOnly
set to true.Create a base class (
FooReadOnly
) where all the mutators throw exceptions, then create a derived class (Foo
) where the mutators work. YourDefault
instance would be of typeFooReadOnly
.
You might look at how DependancyObject(s) and DependanceProperty(s) work in WPF/Silverlight.
Here's an example of how it works in WPF/Silverlight for a class "A" with a property "Foo" with a default value of 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 ); }
}
The disadvantage being that you have to "manually" implement your properties, you can't take advantage of simple "int Foo { get; set; }" syntax, but code snippets can help out quite a bit.
Obviously, If you didn't want to use WPF or Silverlight you'd have to implement all this yourself, but you get the following advantages.
Since, DependancyProperties are objects, they can hold their default value which can be shared by any DependancyObject which hasn't overrided the value.
DependancyObjects keep a list of values only if a value is changed, so objects that are the same as default use up no extra memory.
Since all property set's go through DependancyObject.SetValue, its easy to implement in one place logic for making certain properties or whole objects readonly.
There are other advantages/features which could be added like animation of properties etc but, if you implemented it, you could keep it as simple/complex as you wanted.
精彩评论