Hello everyone!
I have one problem with undo mechanism. Actually, I am currently writting some prototype module outside of CSLA, but I use its undo mechanism. I have a problem with OutOfMemoryException. I really don't understand what is happening. I have simple object vith strings and integers, and 2 properties are of very simple class that has just 3 system type properties (datetime, decimal, and string).
I am using following code for backup and restore:
public void Backup()
{
if (_backup == null)
{
_backup = new Stack<byte[]>();
object source = this;
Type sourceType = source.GetType();
HybridDictionary state = new HybridDictionary();
FieldInfo[] fields;
do
{
// get the list of fields in this type
fields = sourceType.GetFields(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public);
foreach (FieldInfo field in fields)
{
// make sure we process only our variables
if (field.DeclaringType == sourceType)
{
object value = field.GetValue(source);
if (sourceType.IsAssignableFrom(field.FieldType))
{
// make sure the variable has a value
if (value == null)
{
// variable has no value - store that fact
state.Add(field.DeclaringType.Name + "!" + field.Name, null);
}
else
{
// this is a child object, cascade the call
((MyEditObject)value).Backup();
}
}
else
{
// this is a normal field, simply trap the value
state.Add(field.DeclaringType.Name + "!" + field.Name, value);
}
}
}
sourceType = sourceType.BaseType;
}
while (sourceType != null);
// serialize the state and stack it
using (MemoryStream buffer = new MemoryStream())
{
BinaryFormatter formatter = new BinaryFormatter();
formatter.Serialize(buffer, state);
_backup.Push(buffer.ToArray());
}
state.Clear();
state = null;
}
}
public void Restore()
{
// if we are a child object we might be asked to
// undo below the level where stacked states,
// so just do nothing in that case
if (_backup != null)
{
HybridDictionary state;
using (MemoryStream buffer = new MemoryStream(_backup.Pop()))
{
BinaryFormatter formatter = new BinaryFormatter();
buffer.Position = 0;
state = (HybridDictionary)formatter.Deserialize(buffer);
}
object source = this;
Type sourceType = source.GetType();
FieldInfo[] fields;
do
{
// get the list of fields in this type
fields = sourceType.GetFields(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public);
foreach (FieldInfo field in fields)
{
// make sure we process only our variables
if (field.DeclaringType == sourceType)
{
// the field is undoable, so restore its value
object value = field.GetValue(source);
if (sourceType.IsAssignableFrom(field.FieldType))
{
// this is a child object
// see if the previous value was empty
if (state.Contains(field.DeclaringType.Name + "!" + field.Name))
{
// previous value was empty - restore to empty
field.SetValue(source, null);
}
else
{
// make sure the variable has a value
if (value != null)
{
// this is a child object, cascade the call.
((MyEditObject)value).Restore();
}
}
}
else
{
// this is a regular field, restore its value
field.SetValue(source,
state[field.DeclaringType.Name + "!" + field.Name]);
}
}
}
sourceType = sourceType.BaseType;
}
while (sourceType != null);
_backup.Clear();
_backup = null;
state.Clear();
state = null;
}
}
Please, it's urgent. Thanx in advance. All the best.
You probably have a circular reference. Any references to objects other than direct child objects must be marked as NotUndoable (and probably NonSerialized).
You can not use managed backing fields for such references, because all managed object references are assumed to be child references.
Hi Mr. Lhotka,
well, I am sure I don't have circular referencing because, for this matter, I intentionally wrote info classes, lightweight ones that have only system type properties. Thus, no possibility is there for circular reference. Assume I have the following case:
[Serializable]
public class MyObject
{
string name;
int amount;
DateTime date;
SupplierInfo supplier;
}
[Serializable]
public class SupplierInfo
{
string name;
string address;
}
Both classes have encapsulated fields, but i didn't put them here because of simplicity. Also, have on mind that I'm writting this prototype app outside of CSLA, but I wanted to use its mechanism for undoing. In CSLA itself, few months ago, I wrote application that uses undo option, but I didn't have such a problems. What I need in this case is, actually, 1 level undo. So, if you have any suggestions, I appreciate that.
Thank you in advance,
Nebojsha
Hi,
You could also get this OutOfMemory if your restore method gets into an infinite recursive function call.
May not be easy to debug by set VisuaStudio debugger to stop exactly when exception is thrown and check the callstack.
Copyright (c) Marimer LLC