How to set autoincrement Ids in unit test - c#

I'm facing the following scenario:
The IDs of my entities are auto incremented, so I set the setter of all of them to private, but when I want to make a unit test for my domain class I found myself needing to get and set the ID.
How do I go about setting the ID?
public WorkingTime(string name, short numberOfHours, short numberOfShortDays, int workingGroupId)
{
Name = name;
NumberOfHours = numberOfHours;
NumberOfShortDays = numberOfShortDays;
WorkingGroupId = workingGroupId;
ActivatedWorkingTimes = new List<WorkingTimeActivation>();
}
private ICollection<WorkingTimeActivation> _activatedWorkingTimes;
public int Id { get; private set; }
public string Name { get; set; }
public short NumberOfHours { get; set; }
public short NumberOfShortDays { get; set; }
public int WorkingGroupId { get; set; }
public virtual WorkingGroup WorkingGroup { get; set; }
public virtual ICollection<WorkingTimeActivation> ActivatedWorkingTimes { get => _activatedWorkingTimes; set => _activatedWorkingTimes = value; }
Test example:
var workingGroup = new WorkingGroup("WG", 3, Week.Sunday, 2);
workingGroup.AssignedWorkingTimes.Add(new WorkingTime("Winter", 8, 1, 1));
workingGroup.AssignedWorkingTimes.Add(new WorkingTime("Summer", 6, 0, 1));
Now I want to set workingGroupId
Should I use public setter instead ?

Should I use public setter instead ?
Probably not, no.
There are two alternatives to consider.
One is that, if the identifier is really private data, then the test shouldn't need to interact with it directly. We limit the scope of the test to the observable side effects in the model, so that we have the freedom to later change the private implementation details.
Another is that the test is trying to draw your attention to the fact that there are different strategies that you might use for generating the identifier, and that a different strategy might be appropriate in different contexts -- one strategy in use in production code, another for use in the test harness.
The basic pattern isolates the strategy and provides the affordances you need to control which strategy is applied. In the test, we implement the strategy contract using a test double, which allows the test to maintain deterministic control over what would otherwise be an arbitrary side effect.

It seems you are wanting to keep your entities in the domain layer "pure" by creating the private setter. This is a good thing. One way I've handled tests or the mapping of DTOs to entities is by creating an extension method that gives access to the private setter.
This method uses Marc Gravell's FastMember library:
using FastMember;
...
public static class DomainExtensions
{
private static readonly IDictionary<Type, TypeAccessor> _accessors = new Dictionary<Type, TypeAccessor>();
public static T With<T, TFieldOrProperty>(this T instance, Expression<Func<T, TFieldOrProperty>> fieldOrProperty, TFieldOrProperty value)
where T : class
{
if (instance == null)
return null;
if (!(fieldOrProperty.Body is MemberExpression member))
throw new ArgumentException($"Expression '{fieldOrProperty}' is not for a property or field.");
try
{
if (!_accessors.TryGetValue(typeof(T), out var ta))
lock (_accessors)
ta = _accessors[typeof(T)] = TypeAccessor.Create(typeof(T), true);
if (ta[instance, member.Member.Name] != null)
{
ta[instance, member.Member.Name] = value;
return instance;
}
}
catch (Exception e)
{
Debug.WriteLine(e.Message);
}
// fallback to reflection
var fi = member.Member as FieldInfo;
fi?.SetValue(instance, value);
var pi = member.Member as PropertyInfo;
pi?.SetValue(instance, value);
return instance;
}
Then you use it like this:
workingGroup.With(wg => wg.WorkingGroupId, 2);
In this way your entity stays pure. Now you may say, "well I can now bypass the read-only nature of the entity." That's true, but the developer would have to explicitly and mindfully violate this access by calling With().
If test cases are the only place you need this access then put the With() method in the assembly with your tests. This guarantees your production code can't set the ID.

If Id needs to remain private to the class library and also needs to be tested via the testing project, in my opinion, this is the next best option when using C#:
Change the private set; to be an internal set; or create an internal method for setting the Id.
public int Id { get; internal set; }
In your class library that has the class that needs to be tested, in solution explorer, under Properties, in the AssemblyInfo.cs file, add the following line:
[assembly: InternalsVisibleTo("MyTestingAssembly")]
This will make the Internals in your class library that needs to be tested visible to the testing project only. This won't solve the issue of encapsulating Id from other code inside the class library but it will keep the internal concern of Id from being visible to other DLLs that are not testing the class library.

Related

Good practices for an object that will be accessed & updated in many classes in an application?

I have an application that will run once every minute. After completing, the app will write to a log table before it exits. This object closely maps that log table:
class SendResult
{
public DateTime StartTime { get; set; }
public DateTime EndTime { get; set; }
public TimeSpan ExecutionTime { get
{
return EndTime - StartTime;
}
public bool RequestChecked{ get; set; }
public int RequestID { get; set; }
public bool RequestRequiresFileSend { get; set; }
public bool FilesRead { get; set; }
public bool FilesSent { get; set; }
public SendResult() { }
}
Each property will be updated at a different point in the app. I have achieved this by declaring the object once and making it static:
class Program
{
public static SendResult Result;
public Program()
{
Result = new SendResult();
Result.StartTime = DateTime.Now;
// do stuff...
Result.EndTime = DateTime.Now;
LogUtility.Log(Result);
}
}
..and everywhere throughout the app I just call:
Program.Result.FilesRead = ...
I know an alternative is to construct the app around SendResult, like this:
SendResult result = new SendResult();
result.StartTime = DateTime.Now;
var request = new RequestHandler().CheckRequest();
result.RequestChecked = request.Checked;
result.RequestID = request.RequestID;
result.RequestRequiresFileSend = request.FileSendRequired;
var sendResult = new FileSender(request.ResuestID).Send();
result.FilesRead = sendResult.FilesRead;
// ...and so on
But in a case where you have to insert this result tracking after all your code has been written, is there a better way than the global var method I have used?
The parts of the code summarized as "do stuff" should take in the SendResult instance as a dependency that is either explicitly pushed into them, or possibly resolved in some way other than directly depending on accessing a static field in Program. You can pass the reference directly using constructor arguments, object properties, or method parameters. Indirect ways to do that could be implemented using an IoC/DI container. The idea is to reduce coupling, which is most of the time a good idea.
Potentially, your application could benefit from using the Pipes and Filters Architectural Pattern, but only if you have scaleability and flexibility requirements. Otherwise, the introduced complexities would be counterproductive for your particular case.
Static variables are usually not a good idea, there is almost no uses of them in the modern application with Dependency Injection. It's use adds a state and increase coupling, making it much more complicated to e.g. unit test all your components in isolation.
So the simplest approach would be to just create the required object and send it to all the methods that require editing. It's a bit hard to say generally though, it might be better that all your methods do return their own objects that are later composed into the resulting one that is saved to the database.
But while there can be different strategies to achieve what you want, using static variable is most likely not the best of them.

Autofixture and read only properties

Let's consider two version (one with read only properties) of the same very simple entity:
public class Client
{
public Guid Id { get; set; }
public string Name { get; set; }
}
vs
public class Client
{
public Client(Guid id, string name)
{
this.Id = id;
this.Name = name;
}
public Guid Id { get; }
public string Name { get; }
}
When I try to use Autofixture, it will work correctly and as expected with both of them. The problems start, when I try to predefine one of the parameters using .with() method:
var obj = this.fixture.Build<Client>().With(c => c.Name, "TEST").Build();
This will throw error
System.ArgumentException: The property "Name" is read-only.
But it seems that Autofixture knows how to use constructors! And it seems that actual Build<>() method creates an instance of an object not Create()! If build would just prepare builder, with would setup properties, and then Create would instantiate object it would work properly with read only properties.
So why was this (misleading) strategy used here? I've found an answer here that states it's to amplify feedback with tests, but I don't see the usefulness to use FromFactory() especially when a list of parameters is extensive. Wouldn't moving object instantiation from Build() method to Create() method be more intuitive?
I too have struggled with this, since most of my classes are usually readonly. Some libraries like Json.Net use naming conventions to understand what are the constructor arguments that impact each property.
There is indeed a way to customize the property using ISpecimenBuilder interface:
public class OverridePropertyBuilder<T, TProp> : ISpecimenBuilder
{
private readonly PropertyInfo _propertyInfo;
private readonly TProp _value;
public OverridePropertyBuilder(Expression<Func<T, TProp>> expr, TProp value)
{
_propertyInfo = (expr.Body as MemberExpression)?.Member as PropertyInfo ??
throw new InvalidOperationException("invalid property expression");
_value = value;
}
public object Create(object request, ISpecimenContext context)
{
var pi = request as ParameterInfo;
if (pi == null)
return new NoSpecimen();
var camelCase = Regex.Replace(_propertyInfo.Name, #"(\w)(.*)",
m => m.Groups[1].Value.ToLower() + m.Groups[2]);
if (pi.ParameterType != typeof(TProp) || pi.Name != camelCase)
return new NoSpecimen();
return _value;
}
}
Trying to use this on the Build<> api was a dead end as you´ve noticed. So I had to create the extensions methods for myself:
public class FixtureCustomization<T>
{
public Fixture Fixture { get; }
public FixtureCustomization(Fixture fixture)
{
Fixture = fixture;
}
public FixtureCustomization<T> With<TProp>(Expression<Func<T, TProp>> expr, TProp value)
{
Fixture.Customizations.Add(new OverridePropertyBuilder<T, TProp>(expr, value));
return this;
}
public T Create() => Fixture.Create<T>();
}
public static class CompositionExt
{
public static FixtureCustomization<T> For<T>(this Fixture fixture)
=> new FixtureCustomization<T>(fixture);
}
which enabled me to use as such:
var obj =
new Fixture()
.For<Client>()
.With(x => x.Name, "TEST")
.Create();
hope this helps
AutoFixture is, indeed, capable of creating constructor arguments, and invoke constructors. How to control a particular constructor argument is a FAQ, so if that had been the only question, I'd had closed it as a duplicate of Easy way to specify the value of a single constructor parameter?
This post, however, also asks about the design choice behind the behaviour of the Build API, and I will answer that here.
In the second example, Name is a read-only property, and you can't change the value of a read-only property. That's part of .NET (and most other languages) and not a design choice of AutoFixture.
Let's be absolutely clear on this: Name is a property. Technically, it has nothing to do with the class' constructor.
I assume that you consider Name to be associated with the constructor's name argument, because one exposes the other, but we only know that because we have the source code. There's no technically safe way for an external observer to be sure that these two are connected. An outside observer, such as AutoFixture, could attempt to guess that such a connection exists, but there are no guarantees.
It's technically possible to write code like this:
public class Person
{
public Person(string firstName, string lastName)
{
this.FirstName = lastName;
this.LastName = firstName;
}
public string FirstName { get; }
public string LastName { get; }
}
This compiles just fine, even though the values are switched around. AutoFixture would be unable to detect issues like that.
It might be possible to give AutoFixture a heuristic where the Build API attempts to guess 'what you mean' when you refer to a read-only property, but back when I was still the benevolent dictator of the project, I considered that to be a feature with unwarranted complexity. It's possible that the new maintainers may look differently on the topic.
As a general observation, I consider the entire Build API a mistake. In the last many years I wrote tests with AutoFixture, I never used that API. If I still ran the project today, I'd deprecate that API because it leads people into using AutoFixture in a brittle way.
So this is very much an explicit design choice.
Hi I had a similar problem I solved it using `Freeze
_formFileMock = _fixture.Freeze<Mock<IFormFile>>();
_formFileMock.Setup(m => m.ContentType).Returns("image/jpeg");
_fixture.Create<P>

Why use private variables with properties - Code first

A introduce
If you make all your properties virtual then EF will generate proxy classes at runtime that derives from your POCO classed, these proxies allow EF to find out about changes in real time rather than having to capture the original values of your object and then scan for changes when you save (this is obviously has performance and memory usage benefits but the difference will be negligible unless you have a large number of entities loaded into memory). These are known as 'change tracking proxies', if you make your navigation properties virtual then a proxy is still generated but it is much simpler and just includes some logic to perform lazy loading when you access a navigation property.
Reference: http://social.msdn.microsoft.com/Forums/en/adonetefx/thread/99d8d4a1-5ab1-42dc-b9db-5087be02162d
[1]
public virtual ICollection<Log> Logs { get; set; }
[2]
private ICollection<Log> _logs;
public virtual ICollection<Log> Logs
{
get
{
if(_logs == null) Logs = new HashSet<Log>();
return Logs ;
}
private set {}
}
[3]
private ICollection<Log> _logs;
public virtual ICollection<Log> Logs
{
get
{
if(_logs == null) _logs = new HashSet<Log>();
return _logs;
}
set {_logs = value; }
}
How is better thinking in EF - Code first?
Why some people use private fields with properties?
private set can be help to avoid modify the full list
In [1] we can have null references, forcing verify if is null before use the property
But, private variables/fields, I not understand why is necessary. I think propertys in "backend" generate private fields, so?
Like you said, in [1] you can have a null reference exception (usually when you create a new parent class and then you add a new Log.
An approach to avoid it is to:
- write [2]
- initialize it in the parent class constructor
- with c# 5 you can write
public virtual ICollection<Log> Logs { get; set; } = new new HashSet<Log>();
The [3] is not usefull (if you initialize Logs property, EF do not need to access to setter).
Another interesting thing is that you can use your own collection i.e.
public class LogCollection : ObservableCollection<Log>
{
public Post Add(string content)
{
Log log = new Log
{
Date = DateTime.Now,
Content = content
};
Add(log);
return log;
}
}
and then use it in the master class instead of ICollection, i.e.
public virtual LogCollection Logs
{
get
{
if(_logs == null) Logs = new HashSet<Log>();
return Logs ;
};
private set;
}
Usually I initialize collections in class constructor, I don't use backing field and my setter is public (but probably I never used it outside the parent class so it's a stupid way to implement it). But it's my way of work with c# 4.x
EDIT
About a part of your question, EF does not use backing fields, it access only to property setter and getter. You can force to use private backing fields (map backing fields) mapping it via fluent interface and mapping it in an inner class.

How to create a "pointer-like" class, easily exposing functions of member?

What I am trying to do is find the most elegant way to create a "pointer-like" class for a specific object/class type that I have in a project.
What I mean is a little confusing without an example. Take this really simple class:
public class MyClass
{
private string _name;
public string GetName() { return _name; }
public void SetName(string name) { _name = name; }
}
I want to create a second class which is like a pointer to it like this:
public class MyClassPtr
{
private MyClass _obj;
public bool IsValid = false;
public MyClassPtr(MyClass obj) { _obj = obj; IsValid = true; }
public void InvalidatePtr()
{
IsValid = false;
obj = null;
}
// SOME MAGIC HERE?
}
The challenge: The key is that I want to elegantly have MyClassPtr provide an interface to all of the public methods/members in MyClass without writing wrappers and/or accessors around each method/member.
I know that I could do this:
public class MyClassPtr
{
public string GetName() { return _obj.GetName(); }
...
}
But that's what I want to avoid. Is there some fundamental abstraction that I don't know of that I can apply to MyClassPtr to allow it to easily re-expose the methods/members in MyClass directed through _obj? I do NOT want MyClassPtr to inherit MyClass. Should MyClassPtr be a type instead, and some trick with accessors to expose the methods/members of MyClass?
Edit: More context on why I am looking for such a design through an example. Here is the overall goal. Imagine a platform that parses through data about people and when it finds information about a person, it creates an instance of Person with that information. You could get a handle to that person like:
Person person1 = platform.GetPerson(based_on_data);
Now, imagine the platform had two instances of Person that it thought were different people, but all of a sudden information came in that strongly suggested those two instances actually refer to the same person. So, the platform wants to merge the instances together in to a new object, let's call it personX.
Now, floating around in the platform someone had a copy of one of those two instances that got merged, which was person1. What I want to do is on-the-fly replace person1 with personX. Literally, I want person1==personX to be true, NOT just that they are two different objects with the same data. This is important since the platform could make a change to personX and unless the two objects are literally equal, a change to personX would not be automatically reflected in person1.
Since I can't on-the-fly replace person1 with personX I had that idea that I wouldn't give direct access to Person, instead I would give access to PersonPtr which the platform (on-the-fly) can change what Person it is pointing to. This would insurance that once person1ptr gets updated to point to personX, if a change is made in personX it will be seen in person1ptr
You could of course use something like
public class MyClassWrapper
{
MyClass _obj;
public MyClassWrapper(MyClass obj)
{
_obj = obj;
}
public void Invoke(Action<MyClass> action)
{
action(_obj);
}
public U Invoke<U>(Func<MyClass, U> func)
{
return func(_obj);
}
public void ChangeTo(MyClass obj)
{
_obj = obj;
}
}
Given your class looks like
public class MyClass
{
public string Name { get; set; }
}
Example:
var person1 = new MyClass { Name = "Instance1" };
var person2 = new MyClass { Name = "Instance2" };
var wrapper = new MyClassWrapper(person1);
wrapper.Invoke(x => x.Name += "original");
var x = wrapper.Invoke(x => x.Name); // Instance1original
wrapper.ChangeTo(person2);
var y = wrapper.Invoke(x => x.Name); // Instance2
but it has a major drawback: you can't access members directly, so you can't bind the data (to a DataTable or a Control).
It would be better to implement all members of your class also in your wrapper class. If you're afraid changes in your class will be forgotten to be implemented in your wrapper, just use an interface:
public interface IMyClass
{
string Name { get; set; }
}
public class MyClass : IMyClass
{
public string Name { get; set; }
}
public class MyClassWrapper: IMyClass
{
MyClass _obj;
public MyClassWrapper(MyClass obj)
{
_obj = obj;
}
public string Name
{
get { return _obj.Name; }
set { _obj.Name = value; }
}
}
Note that regardless which approach you use, you'll have to always keep a reference to the wrapper instance to actually change the underlying instance (using something like static aside).
Also, changing the underlying instance of such a wrapper without telling the component using it that it changed don't seem to be a good idea. Maybe your system is simple enough to get away with a wrapper; that's something you have to decide for yourself.
Maybe your wrapper should simply have an Invalid flag (and/or use an event to signal a change of the underlying object.). Once the underlying object is merged, it is set to true and each member access should throw an exception. This would force the component using the wrapper to deliberately react to changes and to reload the data from your service.
All in all, I think using such a wrapper will just clutter up your code and be error prone (just imagine adding multithreading to the mix). Think twice if you really need this wrapper.
Why not just simply ask your service for a new instance of your class everytime you use it (the service can simply use a cache)? Sure, you can't prevent that someone somewhere keeps a reference; but at least you'll keep your sanity.

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