Dearest fellow programmers,
I seem to lack some understanding as of how the referencing works in C#.
The case:
I tried to implement some sort of Memento proxy which would wrap an interface and store every parameter that we're provided to the method calls and store these into a list.
Whenever necessary we could call the RestoreState and the objects would "reset" to the original state.
The code:
Consumer and model object
class Program
{
static void Main(string[] args)
{
IMemento memento = new Memento();
PrestationInfo prestationInfo2 = new PrestationInfo { Advance = 2 };
memento.Add(prestationInfo2);
Console.WriteLine(prestationInfo2.Advance); //Expect 2
prestationInfo2.Advance = 1;
Console.WriteLine(prestationInfo2.Advance); //Expect 1
memento.RestoreState();
Console.WriteLine(prestationInfo2.Advance); //Expect 2, but still 1
Console.ReadKey();
}
}
[Serializable]
public class PrestationInfo
{
public int Advance { get; set; }
}
Memento
public interface IMemento
{
void Add(object pItem);
void RestoreState();
}
public class Memento : IMemento
{
public Memento()
{
MementoList = new Dictionary<long, object>();
ReferenceList = new List<object>();
ObjectIDGenerator = new ObjectIDGenerator();
}
private ObjectIDGenerator ObjectIDGenerator { get; set; }
private Dictionary<long, object> MementoList { get; set; }
private List<object> ReferenceList { get; set; }
public void Add(object pItem)
{
bool firstTime;
long id = ObjectIDGenerator.GetId(pItem, out firstTime);
if (firstTime)
{
var mementoObject = DeepCopy(pItem);
MementoList.Add(id, mementoObject);
ReferenceList.Add(pItem);
}
}
public void RestoreState()
{
for (int i = 0; i < ReferenceList.Count; i++)
{
object reference = ReferenceList[i];
bool firstTime;
long id = ObjectIDGenerator.GetId(reference, out firstTime);
if (MementoList.ContainsKey(id))
{
object mementoObject = MementoList[id];
reference = mementoObject;
//reference = PropertyCopy<PrestationInfo>.CopyFrom(mementoObject as PrestationInfo); //Property copy
//Interlocked.Exchange(ref reference, mementoObject); //Also tried this
}
}
}
private static TCopy DeepCopy<TCopy>(TCopy pObjectToCopy)
{
using (MemoryStream memoryStream = new MemoryStream())
{
BinaryFormatter binaryFormatter = new BinaryFormatter();
binaryFormatter.Serialize(memoryStream, pObjectToCopy);
memoryStream.Position = 0;
return (TCopy)binaryFormatter.Deserialize(memoryStream);
}
}
}
Extra info
My guess is, I'm doing/understand something wrong regarding the List.
I also tried the Interlocked.Exchange, playing around with "ref"'s, using WeakReference's and storing the object into a CareTaker object (and storing that CareTaker into the List), implement some copy Property thing...
And ... I just can't see it.
My expected result would be the PrestationInfo.Advance property containing the value 2. But it keeps
Try this:
Change the Add
method:
public long Add(object pItem)
{
bool firstTime;
long id = ObjectIDGenerator.GetId(pItem, out firstTime);
if (firstTime)
{
var mementoObject = DeepCopy(pItem);
MementoList.Add(id, mementoObject);
ReferenceList.Add(pItem);
}
return id; // i need my memento! LOL
}
You should also add this accessor method:
public object GetRestoredState(long id)
{
return MementoList[id]; // you should put some range check here
}
Now that you have your id, you can fetch the restored state this way:
memento.RestoreState();
prestationInfo2 = memento.GetRestoredState(savedId); // <-- you got this when you called the Add()...
Console.WriteLine(prestationInfo2.Advance); //Expect 2, but still 1
Follow ups: you can also make the IMemento
into a IMemento<T>
, and adjust your code accordingly