C # How to create special instances of a class?

For some classes, ideally, I would like to create special named instances similar to "null". As far as I know, this is not possible, so instead I create static instances of the class with a static constructor similar to this:

public class Person { public static Person Waldo; // a special well-known instance of Person public string name; static Person() // static constructor { Waldo = new Person("Waldo"); } public Person(string name) { this.name = name; } } 

As you can see, Person.Waldo is a special instance of the Person class that I created because there are many other classes in my program that might want to refer to this special well-known instance.

The disadvantage of implementing this method is that I do not know how to make all the properties of Person.Waldo immutable, while all the properties of a "normal" instance of Person must be changed. Whenever I accidentally have a Person object related to Waldo, and I do not carelessly check to see if it references Waldo, then I accidentally clobber the Waldo property.

Is there a better way or even some additional alternatives for defining special known instances of a class?

The only solution I know right now is to implement get and set accessors and check "if (this == Waldo) throw new ..." on each set. Although this works, I suggest that C # can do better than me to implement it. If only I can find some C # way to make all Waldo properties readonly (except for the static constructor.)

+6
source share
4 answers

Thanks to all your suggestions, here is the solution. I needed to make a virtual string, override accessors in a public derived class, and use the bool flag to allow modification.

It is important to note that the "name" is a reference type, and although I forbade changing what the "name" means, if it is something other than a string, for example a class that contains a self-modifying method, it would still be possible to change the contents of the object , despite the fact that it did not allow changing the link to the object.

 class Program { static void Main(string[] args) { Person myPerson = new Person("Wenda"); System.Console.WriteLine("myPerson is " + myPerson.name); // Prints "myPerson is Wenda" if (myPerson == Person.Waldo) System.Console.WriteLine("Found Waldo (first attempt)"); // doesn't happen else System.Console.WriteLine("Still trying to find Waldo..."); // Prints "Still trying to find Waldo..." myPerson.name = "Bozo"; System.Console.WriteLine("myPerson is now " + myPerson.name); // Prints "myPerson is now Bozo" myPerson = Person.Waldo; if (myPerson == Person.Waldo) System.Console.WriteLine("Found Waldo (second attempt)"); // Prints "Found Waldo (second attempt)" System.Console.WriteLine("myPerson is " + myPerson.name); // Prints "myPerson is Waldo" System.Console.WriteLine("Now changing to The Joker..."); // Prints "Now changing to The Joker" try { myPerson.name = "The Joker"; // throws ImmutablePersonModificationAttemptException } catch (ImmutablePersonModificationAttemptException) { System.Console.WriteLine("Failed to change"); // Prints "Failed to change" } System.Console.WriteLine("myPerson is now " + myPerson.name); // Prints "myPerson is now Waldo" Thread.Sleep(int.MaxValue); // keep the console alive long enough for me to see the result. } } public class Person { public static readonly ImmutablePerson Waldo = new ImmutablePerson("Waldo"); public virtual string name { get; set; } public Person() // empty base constructor required by ImmutablePerson(string) constructor { } public Person(string name) { this.name = name; } } public class ImmutablePersonModificationAttemptException : Exception { } public class ImmutablePerson : Person { private bool allowMutation; protected string _name; public override string name { get { return _name; } set { if (allowMutation) _name = value; else throw new ImmutablePersonModificationAttemptException(); } } public ImmutablePerson(string name) : base() { allowMutation = true; this.name = name; allowMutation = false; } } 
0
source

Make a private class inside Person that inherits Person, ImmutablePerson : Person .

Make all property locks locked: for example, override them with a NotImplementedException.

Your static character initialization becomes: public static readonly Person Waldo = new ImmutablePerson("Waldo");

And the static constructor can also be removed.

+4
source

You might have the following hierarchy:

 class Person { protected string _name; public virtual string Name{ get{ return _name; } } } class EditablePerson:Person { public new string Name{ get{ return _name; } set{ _name=value; } } public Person AsPerson() { //either return this (and simply constrain by interface) //or create an immutable copy } } 
+1
source

In my opinion, it is best to always return a new copy to Waldo. Thus, the original Waldo will never be changed. But this will not allow you to use referential equality for comparison, so you have to override Equals and GetHashCode.

0
source

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


All Articles