我正在编写一个具有一些对象缓存的应用程序。它需要工作的方式是从缓存中检索对象时:
object foo = CacheProvider.CurrentCache.Get("key");
foo应该是原始对象的本地副本,而不是引用。实现这个的最佳方法是什么?到目前为止,我唯一想到的方法是使用BinarySerializer来创建副本,但我觉得我错过了更好的方法。
缓存实现的支持是任意的,因为它是基于提供程序的。我需要支持任何数量的缓存,从HttpRuntime缓存到类似Velocity。这里的重点是缓存支持和使用者代码之间的层 - 该层必须确保返回对象的副本。一些缓存已经可以做到这一点,但有些不会(HttpRuntime缓存是一个)。
答案 0 :(得分:5)
Rex - 我们在大型企业Web产品中实现了非常类似的东西,最后我们明确地创建了一个IDeepCloneable接口,我们的许多对象都实现了这个接口。有趣的是,我们使用BinarySerializer支持它,只是因为它是一种简单易行的方式来制作对象的深层副本而不需要反思或迫使开发人员编写和测试克隆方法。
它就像一个魅力。我们的团队已经停止了多次考虑,我们还没有找到更好的选择。
答案 1 :(得分:2)
对不起,我一定要解开这个问题。为什么不在字典中查找对象,然后创建对象的深层副本(例如IDeepCopyable
)或使用反射来完成工作?
大致是:
public interface IDeepCopyable {
object DeepCopy();
}
public class Cache<TKey, TValue> where TValue : IDeepCopyable {
Dictionary<TKey, TValue> dictionary = new Dictionary<TKey, TValue>();
// omit dictionary-manipulation code
public TValue this[TKey key] {
get {
return dictionary[key].DeepCopy(); // could use reflection to clone too
}
}
}
如果你去反思路线,马克格拉维尔有一些很好的cloning code很容易修改,以制作深层复制。
答案 2 :(得分:2)
这是一个简单的函数,它将使用反射来深度复制和对象,无论其类型如何。我剔除了这个,部分来自于我在旧的Web服务时代使用的更复杂的复制例程,以复制几乎相同(tm)的数据类型。它可能无法正常工作,它给你一般的想法。这是非常简单的,当使用原始反射时,有许多边界情况......
public static object ObjCopy(object inObj)
{
if( inObj == null ) return null;
System.Type type = inObj.GetType();
if(type.IsValueType)
{
return inObj;
}
else if(type.IsClass)
{
object outObj = Activator.CreateInstance(type);
System.Type fieldType;
foreach(FieldInfo fi in type.GetFields())
{
fieldType = fi.GetType();
if(fieldType.IsValueType) //Value types get copied
{
fi.SetValue(outObj, fi.GetValue(inObj));
}
else if(fieldType.IsClass) //Classes go deeper
{
//Recursion
fi.SetValue(outObj, ObjCopy(fi.GetValue(inObj)));
}
}
return outObj;
}
else
{
return null;
}
}
就个人而言,我会使用Serializer例程,因为它们会自动处理所有边界情况。默认情况下,至少在.NET 2.0中,系统会动态创建序列化程序集。您可以通过缓存序列化程序来加速序列化。我的应用程序中的示例代码正在缓存XmlSerializers。
protected static XmlSerializer SerializerGet(System.Type type)
{
XmlSerializer output = null;
lock(typeof(SerializeAssist))
{
if(serializerList.ContainsKey(type))
{
output = serializerList[type];
}
else
{
if(type == typeof(object) || type == typeof(object[]) || type == typeof(ArrayList))
{
output = new XmlSerializer(type, objArrayTypes);
}
else
{
output = new XmlSerializer(type);
}
serializerList.Add(type, output);
}
}
return output;
}