Using mutable objects as constructor arguments - c#

What is the best practice to pass objects as constructor arguments? Passing mutable objects can lead to unexpected results.
A simple example. We expect 200, but get 10000 calling the TestMethod():
public class Test
{
public int TestMethod()
{
var variable1 = new SomeMeasurements
{
Width = 10,
Height = 20
};
var obj1 = new MyRectangle(variable1);
// <... more code...>
variable1.Height = 1000; // a local variable was reused here, and it's field was changed
// <... more code...>
return obj1.GetArea();
}
}
public class SomeMeasurements
{
public int Width { get; set; }
public int Height { get; set; }
}
public class MyRectangle
{
SomeMeasurements _arg;
public MyRectangle(SomeMeasurements arg)
{
_arg = arg;
}
public int GetArea()
{
return _arg.Width * _arg.Height;
}
}
In this case the error is obvious, but with more complex classes debugging can be tedious. Several things how to fix this have crossed my mind:
option 1. Fix TestMethod() - it mustn't change variable1 after creating MyRectangle.
option 2. Fix class SomeMeasurements - turn it into a struct:
public struct SomeMeasurements
{
public int Width { get; set; }
public int Height { get; set; }
}
option 3. Fix class SomeMeasurements - make it immutable:
public class SomeMeasurements
{
public SomeMeasurements(int width, int height)
{
Width = width;
Height = height;
}
public int Width { get; }
public int Height { get; }
}
option 4. Fix class MyRectangle body - it mustn't use mutable objects:
public class MyRectangle
{
int _height;
int _width;
public MyRectangle(SomeMeasurements arg)
{
_height = arg.Height;
_width = arg.Width;
}
public int GetArea()
{
return _width * _height;
}
}
option 5. Make SomeMeasurements ICloneable and use it's Clone() in MyRectangle constructor.
Any of these options have it's flaws - it might be hard to avoid reusing variable1, MyRectangle can be more complex to turn it into a struct, MyRectangle can be external and you might not change it at all, etc. What is the most correct way to fix this?

Generally you should be passing services that conform to a certain interface, or immutable objects only in constructors. The constructor should take a copy of any mutable data passed to it if you want to protect it from external changes.
Once the data goes through the constructor it should be considered part of the new instance's state, and shouldn't be available for modification outside of that instance.
Your options 3,4 seem most useful. Option 2 would fix the problem because you pass a copy of the data into the constructor. Option 1 may be out of your control in many contexts.

It depends on the relationship between the classes, and what they are designed to do.
If you consider a StreamReader class constructed from a Stream instance, that Stream is expected to continue to be "it's own" mutable class with its own set of responsibilities while the reader deals with its mutability in a given way. There is an ongoing relationship between the two objects, and if one does something to the Stream here, one expects it to affect the reader.
In that case we obviously just hold a reference to the Stream passed to the constructor.
In other cases an object passed to represent the initial state of the object being created. There isn't an ongoing relationship between the two.
Here it's best to copy either the object passed or its fields. (When it comes to micro-opts, copying the fields makes the initial construction very slightly slower and the uses of them very slightly faster).
Which case you are dealing with is something that is part of what you are designing, in that you can decide to make a class work either way. Some cases clearly have to be one or the other (in the StreamReader example it would make no sense to ever not hold on to the Stream you were dealing with), but often there is a choice. Favour the principle of least surprise, and if you still can't make up your mind favour the copying approach where there is no ongoing relationship between the objects as your dependencies are now simpler.

Related

Check if object is defined after initialization in c#

I have the following object (class).
namespace Temp.Models
{
public class CurrentClass
{
private double _firstCoefficient;
private double _secondCoefficient;
public double FirstCoefficient
{
get { return _firstCoefficient; }
set { _firstCoefficient= value; }
}
public double SecondCoefficient
{
get { return _secondCoefficient; }
set { _secondCoefficient= value; }
}
}
}
The following class utilizes the above object and therefore initializes the object as follows:
namespace Temp.Models
{
public class MainClass
{
private CurrentClass _currentClass = new CurrentClass();
public CurrentClass CurrentClass
{
get { return _currentClass; }
set { _currentClass = value; }
}
}
}
At some point if certain conditions are met I would define the variables as follows:
MainClass currentObject = new MainClass();
//if conditions are met
currentObject.CurrentClass.FirstCoefficient = 0;
currentObject.CurrentClass.SecondCoefficient = 5;
But what if the conditions are never met and I never define the above variables. How and/or what is the best way to check if the object was never defined?
I can do the following check:
if(currentObject.CurrentClass.FirstCoefficient != 0 && currentObject.CurrentClass.SecondCoefficent != 0)
But the values can be defined as 0...So I am not sure how to go about this.
Any help is much appreciated!
These are some principles that can be used for solving the problem with description, samples and brief evaluation/opinion.
1. Parametrization through constructors
According to OOP principles, a constructor is method used to initialize an object to a valid state. The concept of immutability takes this even further, disallowing any changes, completely avoiding invalid state.
There is also a possibility of compromise where the API of an object disallows invalid states.
With this concept, you would arrive to:
namespace Temp.Models
{
public class CurrentClass
{
public double FirstCoefficient { get; private set; }
public double SecondCoefficient { get; private set; }
public CurrentClass(double firstCoefficient, double secondCoefficient)
{
FirstCoefficient = firstCoefficient;
SecondCoefficient = secondCoefficient;
}
// if mutability is required - this is needless as the constructor is
// the same but if there was more complex state, methods like this would make
// sense, mutating only parts of the state
public void SetCoefficients(double firstCoefficient, double secondCoefficient)
{
FirstCoefficient = firstCoefficient;
SecondCoefficient = secondCoefficient;
}
}
}
Summary:
Each instantiation of CurrentClass is always in a valid state, avoiding a lot of consistency checks (improved encapsulation)
It takes more code to write (but you save a lot of other code due to the previous point)
You need to know the coefficients beforehand.
2. Using nullable types
Nullable types add the "additional" value to types, the "undefined" state. Reference types (class) are nullable by design while value types (struct) need to be marked nullable, either as Nullable<T> or with the shorthand T?.
This then allows the objects be in invalid state and be specific about it. This goes to the other end of consistency scale from immutability as an object with multiple nullable fields has many invalid states.
Sample code:
namespace Temp.Models
{
public class CurrentClass
{
public double? FirstCoefficient { get; set; }
public double? SecondCoefficient { get; set; }
}
}
Now this gets instantiated quite nicely and can be changed on the fly:
public CurrentClass CreateCurrentClass()
{
var currentClass = new CurrentClass { FirstCoefficient = 1.0 };
var secondCoefficient = RetrieveSecondCoefficient();
currentClass.SecondCoefficient = secondCoefficient;
return currentClass;
}
You'll however need validity checks everywhere the object is used.
public bool IsValid(CurrentClass currentClass)
{
// what if FirstCoefficient has value and SecondCoefficient doesn't,
// is that always an invalid state?
return currentClass.FirstCoefficient.HasValue
&& currentClass.SecondCoefficient.HasValue;
}
Summary:
Very little code is needed to have a DTO up and running
A lot of consistency checks (and related brain pain) are required to work with such model
Encapsulation is lacking - any method taking CurrentClass can alter its validity, therefore making the previous point even worse. This can be eased by usage of read-only interface passed where read-only access is required.
Summing up
There are many other means that usually lay in between the two aforementioned approaches. For example you can use one validity flag (SergeyS's response) per object and ease on the external validity checks but having more code in the class and the need of deeper thinking.
Personally, I prefer immutability. It's more monkey code to write but will definitely pay off down the road thanks to the clean design.
A complex system without immutability is very hard to reason about without extensive knowledge. This is especially painful when working in a team - usually each person only knows a part of the codebase.
The sad thing is that it's not always possible to have evertything immutable (e.g. viewmodels): then I tend to convert objects to an internal immutable model as soon as it's possible.
Given what you already wrote, I would add Initialize() method and Initialized property into your MainClass class. Something similar to this:
public class MainClass
{
private CurrentClass _currentClass = new CurrentClass();
public CurrentClass CurrentClass
{
get { return _currentClass; }
set { _currentClass = value; }
}
public bool Initialized {get; private set;}
public void Initialize()
{
this.CurrentClass.FirstCoefficient = 0;
this.CurrentClass.SecondCoefficient = 5;
this.Initialized = true;
}
}
Call Initialize() method where your conditions met.
Later in code you can just check if(currentObject.Initialized). Notice private setter for `Initialized' property, it will ensure this flag was not accidentally set by external code.
Depending on your needs, you can go further and pass parameters for initialization directly to Initialize() method as parameters.
You have several approaches, like force values to be correct in constructor or have another variable telling if object has no value yet, like System.Drawing.Point has static "Empty" property. But in this case of your simple object your main class is explicitly creating an instance of CurrentClass so at this point this object should be correct and coefficients should be set. If you rely on some other code to set those values to perform some other action later, it is out of scope of these two objects here.
Update: perharps sharing details of what the real problem is would be better, because I have a feeling trying to provide a simpified example ended up in hiding real problem.

With a struct that is a property, what is the standard for updating a value in the struct?

I'm new to C#, and I'm working with a class that has a Rectangle field. I've read that Properties are the most accepted way to declare public fields, so I tried something like this:
public class MyClass
{
public Rectangle MyBox { get; set; }
public UpdateBox(int x, int y)
{
MyBox.X = x;
MyBox.Y = y;
}
}
It won't let me do MyBox.X = x because (from what I've read), Rectangle is a struct, and the getter returns a copy of the Rectangle, so I would not be modifying the value I want.
What is the standard for updating fields like this? I've found two solutions so far:
Creating a new Rectangle to store in the variable:
public class MyClass
{
public Rectangle MyBox { get; set; }
public UpdateBox(int x, int y)
{
MyBox = new Rectangle(x, y, MyBox.Width, MyBox.Height);
}
}
but this seems like it would not be very memory efficient. Then there is just not making Rectangle a property:
public class MyClass
{
public Rectangle MyBox;
public UpdateBox(int x, int y)
{
MyBox.X = x;
MyBox.Y = y;
}
}
What is the standard for this kind of functionality?
By convention you can use a struct as a field and access its internal fields directly, if you want to use it as a property, then make a proper setter for it.
I, personally only use struct types as fields other than properties, maybe a read only property for public access (for encapsulation purposes), grants me safety and general organization of my code.
Your 3rd block of example code is the most correct form in my view, and no its not memory inefficient, Rectangle MyBox is already allocated in memory and already consuming its most by the time the constructor is called.
Also, let us keep in mind here, a property is a "shortcut" function to access some data, but if this data ought to be stored somewhere and wont likely change (default get/set accessors), then it's not any different from a normal field.
This is my favorite way of dealing with this:
public class MyClass
{
private Rectangle _MyBox; // or protected idk.
// This is public and read only.
public Rectangle MyBox { get { return _MyBox; } }
public UpdateBox(int x, int y)
{
_MyBox.X = x;
_MyBox.Y = y;
}
}
The clearest approach for non-speed-critical applications is to use the pattern:
var temp=myThing.TheProperty;
temp.X = whatever;
temp.Y = whatever;
myThing.TheProperty = temp;
If the structure behaves as a bunch of independent variables fastened together with duct tape, the above approach will avoid having to either have the client code know about all of its fields, or have the struct include lots of boilerplate WithX, WithY, etc. factory methods.
If speed is important, then one should either have structures exposed in fields or arrays [as opposed to other collection types], or--if one wants to retain encapsulation--include accessor methods:
delegate void ActionRR<T1,T2>(ref T1 p1, ref T2 p2);
void ActOnBounds<TExtra>(ref Rectangle bounds, ActionRR<Rectangle, TExtra>proc, ref TExtra extra)
{
proc(ref _bounds, ref extra);
}
Note that generating delegates to call ActOnBounds will make it slow, but it may be used efficiently by passing a static delegate and a ref valuetype. Unfortunately, while C# includes lots of nice syntactic sugar for closures, it does not provide such help with constructs like the above.

Struct with auto-implemented properties and constructor initializer

Recently a compiler warning and (very useful) hint prompted me to write the code below.
I had no idea you could do this, but it is perfectly legal, and also convenient in that I can declare a managed struct with public properties similar to public fields of an unmanaged struct, and also initialize it with an object instead of having to pass all the fields as parameters.
What confuses me is that this appears to call the explicit parameterless constructor, which would of course be illegal for this struct.
What's going on here, and has this syntax always been supported?
internal struct IconEntry
{
public byte Width { get; set; }
public byte Height { get; set; }
public byte ColorCount { get; set; }
public byte Reserved { get; set; }
public short Planes { get; set; }
public short BitCount { get; set; }
public int BytesInRes { get; set; }
public int ImageOffset { get; set; }
public IconEntry(BinaryReader reader)
: this()
{
Width = reader.ReadByte();
Height = reader.ReadByte();
ColorCount = reader.ReadByte();
Reserved = reader.ReadByte();
Planes = reader.ReadInt16();
BitCount = reader.ReadInt16();
BytesInRes = reader.ReadInt32();
ImageOffset = reader.ReadInt32();
}
}
A struct always has a public parameterless constructor which can't be overriden: http://msdn.microsoft.com/en-us/library/aa288208%28v=vs.71%29.aspx
This means that a user still would be able to create an instance of this struct that is not initialized according to your logic but with default values for all properties:
var s = new IconEntry();
All structs have a parameterless constructor - it's just implicit (e.g. it always exists with a default routine - one that sets all values to 0) - you just can't have an explicit one (e.g. one that you define yourself in code).
Is there any reason you're exposing properties rather than fields for your struct? If the semantics of your data type imply that
The entire state of an instance will be fully defined by the values exposed by some public members, such that two instances for whom all those report or contain identical values will be considered identical.
Instances of the struct with any combination of values for the aforementioned members may be created easily, given the desired values in question.
that sounds like a perfect fit for a PODS (Plain Old Data Struct). Exposed fields are more efficient and less quirky than struct properties. Given that all struct types always expose all fields for mutation or capture by struct assignment, the encapsulation offered by struct properties is of extremely limited value.
The way you have your constructor written, your struct will have all fields set to all-bits-zero, and then be passed repeatedly to methods which will update one field at a time with the desired value. The fact that the struct is specified as initialized to all-bits-zero by the this will make the compiler happy, but using many individual properties to set up fields piecemeal is inefficient.
Incidentally, even better than a constructor in many cases would be a static method which simply takes your struct as a ref parameter. In many cases, using a constructor with a struct will result in an unnecessary copy operation which could be avoided by using a static method with a ref parameter.
Since structs are value types, it's data members should be initialized if you are explicitly invoke the constructor. And mention "this()" to intimate compiler to complete the assignment of auto implemented properties if anything you mentioned.
struct Student
{
string _sname;
public int ID
{
get; set;
}
internal Student(string sname):this()
{
_sname = sname;
}
internal void PrintDetails()
{
Console.WriteLine("ID : {0} Name: {1}", ID, _sname);
}
}
Main method:
class Program
{
static void Main()
{
Student st = new Student("John")
{
ID=101
};
st.PrintDetails();
}
}
Output:
ID : 101 Name: John
If you are not mention "this()", compiler forcefully ask you to complete the full assignment of ID property.
If you are not explicitly invoke the constructor, compiler implicitly set default values for the struct data members.

CA1819: Properties shouldn't return arrays - What is the right alternative?

I encountered this FxCop rule before and wasn't really content with how to solve violations (thread1, thread2). I now have another case where I need to correct violations of the CA1819 kind.
Specifically, I have an algorithm-library that performs some analytic calculations on a curve (x,y), with a public "input object" like this:
public class InputObject
{
public double[] X { get; set; }
public double[] Y { get; set; }
// + lots of other things well
}
This object's X and Y properties are used in hundreds of locations within library, typically using indexes. The input object is never altered by the algorithms, but actually it shouldn't matter if so. Also, .Length is called pretty frequently. It's a mathematical library, and double[] is kind of the standard data type in there. In any case, fixing CA1819 will require quite some work.
I thought about using List<double>, since Lists support indexing and are quite similar to arrays but I'm not sure whether this may slow down the algorithms or whether FxCop will be happy with those Lists.
What is the best option to replace these double[] properties?
If it is read only to external consumer and consumer does not want to access it by index then the best is to have a public read only property of type IEnumerable<> with method accessors to add and remove, this way you will not have to expose your array to someone to mess with.
If you need to access the indexers then expose it as read only property of type IList<> and probably return a ReadOnly instance, with methods to add and remove.
This way you keep encapsulation of the internal list and allow consumer to access it in a read only way
Sometime FxCop from my point of view exagerates.
It all depends on what you have to do, if you are writing a complex system where security and very clean code is required, you should returns a readonly version of that array.
That is, cast the array as IEnumerable as suggests devdigital or use the good idea ImmutableArray of Mohamed Abed, that i prefer.
If your are writing software that require high performance... there is nothing better than an array for performances in C#.
Arrays can be a lot more performant for iterating and reading.
If performances are really important I suggest you to ignore that warning.
Is still legal, also if not too much clean, to return a readonly array.
for (int i = 0; i < array.Length; ++i) { k = array[i] + 1; }
This is very fast for big arrays in C#: it avoids array bounds check.
It will perform very much as a C compiled code would do.
I always wished a "readonly array" type in C# :) but there is no hope to see it.
As your link suggests:
To fix a violation of this rule, either make the property a method or
change the property to return a collection.
Using a collection such as a List should not have a significant impact on performance.
The big problem here isn't really what your library does with the values (which is a potential problem, albeit a much more manageable one), but rather what callers might do with the values. If you need to treat them as immutable, then you need to ensure that a library consumer cannot change the contents after their original assignment. The easy fix here would be to create an interface that exposes all the array members that your library uses, then create an immutable wrapper class for an array that implements this interface to use in your InputObject class. e.g.:
public interface IArray<T>
{
int Length { get; }
T this[int index] { get; }
}
internal sealed class ImmutableArray<T> : IArray<T>
where T : struct
{
private readonly T[] _wrappedArray;
internal ImmutableArray(IEnumerable<T> data)
{
this._wrappedArray = data.ToArray();
}
public int Length
{
get { return this._wrappedArray.Length; }
}
public T this[int index]
{
get { return this._wrappedArray[index]; }
}
}
public class InputObject
{
private readonly IArray<double> _x;
private readonly IArray<double> _y;
public InputObject(double[] x, double[] y)
{
this._x = new ImmutableArray<double>(x);
this._y = new ImmutableArray<double>(y);
}
public IArray<double> X
{
get { return this._x; }
}
public IArray<double> Y
{
get { return this._y; }
}
//...
}
The elements in your "immutable" array contents would still be mutable if T is mutable, but at least you're safe for the double type.
Change array [] to IEnumerable:
public class InputObject
{
public IEnumerable<double> X { get; set; }
public IEnumerable<double> Y { get; set; }
// + lots of other things well
}

What is a "mostly complete" (im)mutability approach for C#? [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 6 years ago.
Improve this question
Since immutability is not fully baked into C# to the degree it is for F#, or fully into the framework (BCL) despite some support in the CLR, what's a fairly complete solution for (im)mutability for C#?
My order of preference is a solution consisting of general patterns/principles compatible with
a single open-source library with few dependencies
a small number of complementary/compatible open-source libraries
something commercial
that
covers Lippert's kinds of immutability
offers decent performance (that's vague I know)
supports serialization
supports cloning/copying (deep/shallow/partial?)
feels natural in scenarios such as DDD, builder patterns, configuration, and threading
provides immutable collections
I'd also like to include patterns you as the community might come up with that don't exactly fit in a framework such as expressing mutability intent through interfaces (where both clients that shouldn't change something and may want to change something can only do so through interfaces, and not the backing class (yes, I know this isn't true immutability, but sufficient):
public interface IX
{
int Y{ get; }
ReadOnlyCollection<string> Z { get; }
IMutableX Clone();
}
public interface IMutableX: IX
{
new int Y{ get; set; }
new ICollection<string> Z{ get; } // or IList<string>
}
// generally no one should get ahold of an X directly
internal class X: IMutableX
{
public int Y{ get; set; }
ICollection<string> IMutableX.Z { get { return z; } }
public ReadOnlyCollection<string> Z
{
get { return new ReadOnlyCollection<string>(z); }
}
public IMutableX Clone()
{
var c = MemberwiseClone();
c.z = new List<string>(z);
return c;
}
private IList<string> z = new List<string>();
}
// ...
public void ContriveExample(IX x)
{
if (x.Y != 3 || x.Z.Count < 10) return;
var c= x.Clone();
c.Y++;
c.Z.Clear();
c.Z.Add("Bye, off to another thread");
// ...
}
Would the better solution be to just use F# where you want true immutability?
Use this T4 template I put together to solve this problem. It should generally suit your needs for whatever kinds of immutable objects you need to create.
There's no need to go with generics or use any interfaces. For my purposes, I do not want my immutable classes to be convertible to one another. Why would you? What common traits should they share that means they should be convertible to one another? Enforcing a code pattern should be the job of a code generator (or better yet, a nice-enough type system to allow you to do define general code patterns, which C# unfortunately does not have).
Here's some example output from the template to illustrate the basic concept at play (nevermind the types used for the properties):
public sealed partial class CommitPartial
{
public CommitID ID { get; private set; }
public TreeID TreeID { get; private set; }
public string Committer { get; private set; }
public DateTimeOffset DateCommitted { get; private set; }
public string Message { get; private set; }
public CommitPartial(Builder b)
{
this.ID = b.ID;
this.TreeID = b.TreeID;
this.Committer = b.Committer;
this.DateCommitted = b.DateCommitted;
this.Message = b.Message;
}
public sealed class Builder
{
public CommitID ID { get; set; }
public TreeID TreeID { get; set; }
public string Committer { get; set; }
public DateTimeOffset DateCommitted { get; set; }
public string Message { get; set; }
public Builder() { }
public Builder(CommitPartial imm)
{
this.ID = imm.ID;
this.TreeID = imm.TreeID;
this.Committer = imm.Committer;
this.DateCommitted = imm.DateCommitted;
this.Message = imm.Message;
}
public Builder(
CommitID pID
,TreeID pTreeID
,string pCommitter
,DateTimeOffset pDateCommitted
,string pMessage
)
{
this.ID = pID;
this.TreeID = pTreeID;
this.Committer = pCommitter;
this.DateCommitted = pDateCommitted;
this.Message = pMessage;
}
}
public static implicit operator CommitPartial(Builder b)
{
return new CommitPartial(b);
}
}
The basic pattern is to have an immutable class with a nested mutable Builder class that is used to construct instances of the immutable class in a mutable way. The only way to set the immutable class's properties is to construct a ImmutableType.Builder class and set that in the normal mutable way and convert that to its containing ImmutableType class with an implicit conversion operator.
You can extend the T4 template to add a default public ctor to the ImmutableType class itself so you can avoid a double allocation if you can set all the properties up-front.
Here's an example usage:
CommitPartial cp = new CommitPartial.Builder() { Message = "Hello", OtherFields = value, ... };
or...
CommitPartial.Builder cpb = new CommitPartial.Builder();
cpb.Message = "Hello";
...
// using the implicit conversion operator:
CommitPartial cp = cpb;
// alternatively, using an explicit cast to invoke the conversion operator:
CommitPartial cp = (CommitPartial)cpb;
Note that the implicit conversion operator from CommitPartial.Builder to CommitPartial is used in the assignment. That's the part that "freezes" the mutable CommitPartial.Builder by constructing a new immutable CommitPartial instance out of it with normal copy semantics.
Personally, I'm not really aware of any third party or previous solutions to this problem, so my apologies if I'm covering old ground. But, if I were going to implement some kind of immutability standard for a project I was working on, I would start with something like this:
public interface ISnaphot<T>
{
T TakeSnapshot();
}
public class Immutable<T> where T : ISnaphot<T>
{
private readonly T _item;
public T Copy { get { return _item.TakeSnapshot(); } }
public Immutable(T item)
{
_item = item.TakeSnapshot();
}
}
This interface would be implemented something like:
public class Customer : ISnaphot<Customer>
{
public string Name { get; set; }
private List<string> _creditCardNumbers = new List<string>();
public List<string> CreditCardNumbers { get { return _creditCardNumbers; } set { _creditCardNumbers = value; } }
public Customer TakeSnapshot()
{
return new Customer() { Name = this.Name, CreditCardNumbers = new List<string>(this.CreditCardNumbers) };
}
}
And client code would be something like:
public void Example()
{
var myCustomer = new Customer() { Name = "Erik";}
var myImmutableCustomer = new Immutable<Customer>(myCustomer);
myCustomer.Name = null;
myCustomer.CreditCardNumbers = null;
//These guys do not throw exceptions
Console.WriteLine(myImmutableCustomer.Copy.Name.Length);
Console.WriteLine("Credit card count: " + myImmutableCustomer.Copy.CreditCardNumbers.Count);
}
The glaring deficiency is that the implementation is only as good as the client of ISnapshot's implementation of TakeSnapshot, but at least it would standardize things and you'd know where to go searching if you had issues related to questionable mutability. The burden would also be on potential implementors to recognize whether or not they could provide snapshot immutability and not implement the interface, if not (i.e. the class returns a reference to a field that does not support any kind of clone/copy and thus cannot be snapshot-ed).
As I said, this is a start—how I'd probably start—certainly not an optimal solution or a finished, polished idea. From here, I'd see how my usage evolved and modify this approach accordingly. But, at least here I'd know that I could define how to make something immutable and write unit tests to assure myself that it was.
I realize that this isn't far removed from just implementing an object copy, but it standardizes copy vis a vis immutability. In a code base, you might see some implementors of ICloneable, some copy constructors, and some explicit copy methods, perhaps even in the same class. Defining something like this tells you that the intention is specifically related to immutability—I want a snapshot as opposed to a duplicate object because I happen to want n more of that object. The Immtuable<T> class also centralizes the relationship between immutability and copies; if you later want to optimize somehow, like caching the snapshot until dirty, you needn't do it in all implementors of copying logic.
If the goal is to have objects which behave as unshared mutable objects, but which can be shared when doing so would improve efficiency, I would suggest having a private, mutable "fundamental data" type. Although anyone holding a reference to objects of this type would be able to mutate it, no such references would ever escape the assembly. All outside manipulations to the data must be done through wrapper objects, each of which holds two references:
UnsharedVersion--Holds the only reference in existence to its internal data object, and is free to modify it
SharedImmutableVersion--Holds a reference to the data object, to which no references exist except in other SharedImmutableVersion fields; such objects may be of a mutable type, but will in practice be immutable because no references will ever be made available to code that would mutate them.
One or both fields may be populated; when both are populated, they should refer to instances with identical data.
If an attempt is made to mutate an object via the wrapper and the UnsharedVersion field is null, a clone of the object in SharedImmutableVersion should be stored in UnsharedVersion. Next, SharedImmutableCVersion should be cleared and the object in UnsharedVersion mutated as desired.
If an attempt is made to clone an object, and SharedImmutableVersion is empty, a clone of the object in UnsharedVersion should be stored into SharedImmutableVersion. Next, a new wrapper should be constructed with its UnsharedVersion field empty and its SharedImmutableVersion field populated with the SharedImmutableVersion from the original.
It multiple clones are made of an object, whether directly or indirectly, and the object hasn't been mutated between the construction of those clones, all clones will refer to the same object instance. Any of those clones may be mutated, however, without affecting the others. Any such mutation would generate a new instance and store it in UnsharedVersion.

Categories

Resources