Static immutable default instance

I like being able to provide default values ​​for classes that can be used, but the problem is that if they are changed, they will affect all references to it and will not be "default". Using a default value such as this, it stores in memory and allows the default, if you like, to apply to all links that use the default value.

A simple example is

class A { static public A Default; } 

You can then use A.Default as a “standard” instance of A. Again, the problem is that A is not immutable or at least “frozen” and changes to it will change all links. This may be good if this is the behavior that is required, but can cause chaos if the default was changed accidentally.

What I really need is a way of deep freezing and thawing.

Obviously, one way is to simply configure all setters only on a condition and mark collections as read-only. It seems like a lot of repetitive work to provide such simple behavior.

Is there a simple library, template, or reflection to accomplish this? The ability to copy to write would be nice, so if the default attempt is changed, a new mutable instance will be created. Not only this, even a fly instance can be created if it has a chance to increase productivity (size of changes).

Example. Suppose you first created 1 MB objects (memory size) with all the same state. Using the default template, this will create only 1 actual object. Suppose you change 1 parameter for all states (say, position), but the object itself is very large. Using the flyweight template, you will only have 1M changed parameters to track (slower but less memory, as usual) instead of 1M new objects. After enough parameters have been changed, an object with full blowing will finally be assigned to it by reference.

Is there anything there?

+4
source share
4 answers

One of the possible methods that I use is to implement a read-only interface and change the static default return type:

 interface ISomeClass { string MyProperty { get; } } class SomeClass : ISomeClass { string MyProperty { get; set; } public static ISomeClass Default = new SomeClass(); } 

Then you can forcibly establish that any default time change is required, the changed link is explicitly requested, possibly using a separate method:

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

Then you get a compile-time check that any method trying to change an instance of SomeClass does not use the default unless it explicitly says so.

+2
source

There is nothing like this out of the box. You need to create your own instance and code to copy to write.

What you need to do for real behavior when copying to write:

  • Create a small “link” object, and each time someone reads the “ Default ” property, it returns a new instance. This object always refers to the same (private, by definition read-only) internal data.

  • Whenever the data changes and you are still in read-only data, create a copy of the internal data and assign it to your reference object.

The developers of the .NET Framework have taken a more explicit route for some classes with similar requirements. If you look at CultureInfo , for example, the default instances are read-only, and if you try to change them, you will get an exception. However, you can easily create a mutable copy (one of the constructors accepts another instance of CultureInfo ).

0
source

There are several ways to do this to spring:

  • Have a flag called IsReadOnly so that all your mutators (setters and methods that can modify the instance) throw an exception when it is true. Your Default instance will be created with IsReadOnly set to true.

  • Create a base class ( FooReadOnly ) where all mutators throw exceptions, then create a derived class ( Foo ) where the mutators work. Your Default instance will be of type FooReadOnly .

0
source

You can see how DependancyObject (s) and DependanceProperty (s) work in WPF / Silverlight.

Here is an example of how it works in WPF / Silverlight for class "A" with the "Foo" property 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 downside is that you have to "manually" implement your properties, you cannot use the simple syntax "int Foo {get; set;}", but code snippets can help a bit.

Obviously, if you do not want to use WPF or Silverlight, you will have to implement all this yourself, but you will get the following benefits.

Since DependancyProperties are objects, they can retain their default value, which can be used by any DependancyObject that has not overridden the value.

DependancyObjects only maintains a list of values ​​if the value is changed, so objects that are the same as the default do not use additional memory.

Since the entire set of properties passes through DependancyObject.SetValue, it is easy to implement logic in one place in order to make certain properties or entire objects readonly.

There are other advantages / features that you can add as animating properties, etc., but if you have implemented it, you can save it as simple / complex as you like.

0
source

Source: https://habr.com/ru/post/1342519/


All Articles