LiteMDA中用于实体类的Cloneable默认Generic简单实现
类Cloneable<T>实现了LiteMDA.Common.ICloneable<T>以及System.ICloneable接口,可以作为基类为实体类提供Clone()支持。因为还是不得不基于反射,虽然加入了部分缓存,性能肯定还是会受影响,如果对性能要求较高则还需为实体类手动实现LiteMDA.Common.ICloneable<T>和System.ICloneable接口。实际的实现中,Cloneable<T>隐藏了object System.ICloneable.Clone()而只暴露T LiteMDA.Common.ICloneable<T>.Clone()。
由于实际使用中,对于应用于实体类来讲,原则上要么是值类型或者string类型,要么就必须实现LiteMDA.Common.ICloneable<T>接口,因此,用于实体类的基类时,Cloneable<T>原则上不会发生Clone出的对象内的某个成员和被Clone成员指向同一个对象实例的情况。
不过如果对于其它对类型没有以上限制的地方请慎用,一般会报错!
ICloneable.cs
using System;
using System.Collections.Generic;
using System.Text;
namespace LiteMDA.Common
{
public interface ICloneable<T>
{
T Clone();
}
}
using System.Collections.Generic;
using System.Text;
namespace LiteMDA.Common
{
public interface ICloneable<T>
{
T Clone();
}
}
Cloneable.cs
using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;
namespace LiteMDA.Common
{
public abstract class Cloneable<T> : ICloneable<T>, ICloneable
where T : new()
{
#region Static Cache Support
private static Dictionary<Type, FieldInfo[]> TypeFieldCache = new Dictionary<Type, FieldInfo[]>();
#endregion
#region ICloneable<T> Members
public T Clone()
{
T retObj = new T();
FieldInfo[] fis = null;
if (TypeFieldCache.ContainsKey(this.GetType()))
{
fis = TypeFieldCache[this.GetType()];
}
else
{
fis = this.GetType().GetFields(BindingFlags.CreateInstance | BindingFlags.GetField | BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.SetField);
TypeFieldCache[this.GetType()] = fis;
}
if (fis != null && fis.Length > 0)
{
foreach (FieldInfo fi in fis)
{
object fiValue = fi.GetValue(this);
if (fi.FieldType.IsValueType)
{
fi.SetValue(retObj, fi.GetValue(this));
}
else if (fiValue != null)
{
if (fi.FieldType == typeof(string))
{
fi.SetValue(retObj, fiValue.ToString().Clone());
}
else if (fi.FieldType.IsSubclassOf(Type.GetType("LiteMDA.Common.Cloneable`1").MakeGenericType(fi.FieldType)) || fiValue is ICloneable)
{
//if cloneable
fi.SetValue(retObj, fi.FieldType.GetMethod("Clone").Invoke(fiValue, null));
}
else
{
throw new Exception(string.Format("Object type '{0}' is not supported by LiteMDA.Common.Cloneable<T>!", fi.FieldType.ToString()));
}
}
else
{
fi.SetValue(retObj, null);
}
}
}
return retObj;
}
#endregion
#region ICloneable Members
object ICloneable.Clone()
{
return this.Clone();
}
#endregion
}
}
using System.Collections.Generic;
using System.Text;
using System.Reflection;
namespace LiteMDA.Common
{
public abstract class Cloneable<T> : ICloneable<T>, ICloneable
where T : new()
{
#region Static Cache Support
private static Dictionary<Type, FieldInfo[]> TypeFieldCache = new Dictionary<Type, FieldInfo[]>();
#endregion
#region ICloneable<T> Members
public T Clone()
{
T retObj = new T();
FieldInfo[] fis = null;
if (TypeFieldCache.ContainsKey(this.GetType()))
{
fis = TypeFieldCache[this.GetType()];
}
else
{
fis = this.GetType().GetFields(BindingFlags.CreateInstance | BindingFlags.GetField | BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.SetField);
TypeFieldCache[this.GetType()] = fis;
}
if (fis != null && fis.Length > 0)
{
foreach (FieldInfo fi in fis)
{
object fiValue = fi.GetValue(this);
if (fi.FieldType.IsValueType)
{
fi.SetValue(retObj, fi.GetValue(this));
}
else if (fiValue != null)
{
if (fi.FieldType == typeof(string))
{
fi.SetValue(retObj, fiValue.ToString().Clone());
}
else if (fi.FieldType.IsSubclassOf(Type.GetType("LiteMDA.Common.Cloneable`1").MakeGenericType(fi.FieldType)) || fiValue is ICloneable)
{
//if cloneable
fi.SetValue(retObj, fi.FieldType.GetMethod("Clone").Invoke(fiValue, null));
}
else
{
throw new Exception(string.Format("Object type '{0}' is not supported by LiteMDA.Common.Cloneable<T>!", fi.FieldType.ToString()));
}
}
else
{
fi.SetValue(retObj, null);
}
}
}
return retObj;
}
#endregion
#region ICloneable Members
object ICloneable.Clone()
{
return this.Clone();
}
#endregion
}
}
//文章结束