A couple days ago I was exterminating the French (Medieval 2: Total War), when I realized that there was a flaw in the caching scheme that I set up for the HaterAide ORM. Mainly when I save an item (an update, not an insert), I overwrite the object with whatever is passed in. This however could lead to an object being in there multiple times as it would save all of the current information, including objects. This could lead to a lot of information being out of sync... For instance if I have object A which holds object B and I save A, caching A. Then lets say that I update B and save B, caching B seperately. When I load A, because the ORM's caching system is dumb, it wont know that B has been updated and simply give us the out of date information.
So after a bit of thought, I came to the conclusion that I needed to make a copy. But really only a shallow copy, and actually it needed to be a shallow copy that ignored objects... So I came up with a couple functions to help me accomplish this:
/// <summary>
/// Makes a shallow copy of the object
/// </summary>
/// <param name="Object">Object to copy</param>
/// <param name="SimpleTypesOnly">If true, it only copies simple types (no classes, only items like int, string, etc.), false copies everything.</param>
/// <returns>A copy of the object</returns>
public static object MakeShallowCopy(object Object,bool SimpleTypesOnly)
{
Type ObjectType = Object.GetType();
PropertyInfo[] Properties = ObjectType.GetProperties();
FieldInfo[] Fields = ObjectType.GetFields();
object ClassInstance = Activator.CreateInstance(ObjectType);
foreach (PropertyInfo Property in Properties)
{
try
{
if (SimpleTypesOnly)
{
SetPropertyifSimpleType(Property, ClassInstance, Object);
}
else
{
SetProperty(Property, ClassInstance, Object);
}
}
catch { }
}
foreach (FieldInfo Field in Fields)
{
try
{
if (SimpleTypesOnly)
{
SetFieldifSimpleType(Field, ClassInstance, Object);
}
else
{
SetField(Field, ClassInstance, Object);
}
}
catch { }
}
return ClassInstance;
}
/// <summary>
/// Copies a field value
/// </summary>
/// <param name="Field">Field object</param>
/// <param name="ClassInstance">Class to copy to</param>
/// <param name="Object">Class to copy from</param>
private static void SetField(FieldInfo Field, object ClassInstance, object Object)
{
try
{
if (Field.IsPublic)
{
Field.SetValue(ClassInstance, Field.GetValue(Object));
}
}
catch { }
}
/// <summary>
/// Copies a field value
/// </summary>
/// <param name="Field">Field object</param>
/// <param name="ClassInstance">Class to copy to</param>
/// <param name="Object">Class to copy from</param>
private static void SetFieldifSimpleType(FieldInfo Field, object ClassInstance, object Object)
{
Type FieldType = Field.FieldType;
if(Field.FieldType.FullName.StartsWith("System.Collections.Generic.List", StringComparison.CurrentCultureIgnoreCase))
{
FieldType=Field.FieldType.GetGenericArguments()[0];
}
if (FieldType.FullName.StartsWith("System"))
{
SetField(Field, ClassInstance, Object);
}
}
/// <summary>
/// Copies a property value
/// </summary>
/// <param name="Property">Property object</param>
/// <param name="ClassInstance">Class to copy to</param>
/// <param name="Object">Class to copy from</param>
private static void SetPropertyifSimpleType(PropertyInfo Property, object ClassInstance, object Object)
{
Type PropertyType = Property.PropertyType;
if (Property.PropertyType.FullName.StartsWith("System.Collections.Generic.List", StringComparison.CurrentCultureIgnoreCase))
{
PropertyType = Property.PropertyType.GetGenericArguments()[0];
}
if (PropertyType.FullName.StartsWith("System"))
{
SetProperty(Property, ClassInstance, Object);
}
}
/// <summary>
/// Copies a property value
/// </summary>
/// <param name="Property">Property object</param>
/// <param name="ClassInstance">Class to copy to</param>
/// <param name="Object">Class to copy from</param>
private static void SetProperty(PropertyInfo Property, object ClassInstance, object Object)
{
try
{
if (Property.GetSetMethod() != null && Property.GetGetMethod() != null)
{
Property.SetValue(ClassInstance, Property.GetValue(Object, null), null);
}
}
catch { }
}
I know it's a bit of code but in order to use it, you simply call MakeShallowCopy, feeding it the object and whether or not you want it to copy simple types only (I should really call it System types...) or everything. It then gets the list of properties and fields from the object and procedes to copy that information to a newly created object which it then passes back. It's not perfect mind you, but it should do the job for my needs and hopefully can be of some use to someone else out there. Anyway, take a look, leave feedback, and happy coding.
e39f1d04-5f7b-46b8-851d-bc962bdc9357|0|.0