独立的通用纪念品
本文关键字:纪念品 独立 | 更新日期: 2023-09-27 18:14:58
亲爱的程序员们,
我似乎对c#中的引用是如何工作的缺乏一些理解。
案例:
我试图实现某种Memento代理,它将包装一个接口,并存储我们提供给方法调用的每个参数,并将它们存储到一个列表中。
只要有必要,我们可以调用RestoreState,对象就会"重置"到原始状态。
代码:
消费者和模型对象
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; }
}
纪念品
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);
}
}
}
额外信息
我的猜测是,我对这个列表的理解有问题。
我也试过Interlocked。交换,使用"ref"'s,使用WeakReference's并将对象存储到一个看守对象中(并将看守对象存储到List中),实现一些复制属性的东西…
…我就是看不出来。
我期望的结果是PrestationInfo。包含值2的高级属性。但是它保持
试试这个:
更改Add
方法:
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
}
您还应该添加以下访问器方法:
public object GetRestoredState(long id)
{
return MementoList[id]; // you should put some range check here
}
现在你有了你的id,你可以这样获取恢复状态:
memento.RestoreState();
prestationInfo2 = memento.GetRestoredState(savedId); // <-- you got this when you called the Add()...
Console.WriteLine(prestationInfo2.Advance); //Expect 2, but still 1
后续:您也可以将IMemento
变为IMemento<T>
,并相应地调整代码
纪念品。Add需要一个ref形参修饰符来访问原始的引用类型指针。
https://msdn.microsoft.com/en-us/library/14akc2c7.aspx?f=255& MSPPError = -2147217396
看起来问题出在你对。net中引用的理解上
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
}
}
}
上面的RestoreState方法不返回任何东西,并且严格地操作引用,而不是它们的内部状态。在你的方法中,object reference
是一个本地引用。它与外部prestationInfo2
不同,您的方法只是使reference
指向(引用)以前保存的presentationInfo2
状态副本。
你可以这样修改:
public object 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;
return reference;
}
}
return null;
}
然后像这样调用它:
presentationInfo2 = memento.RestoreState();
如果你想让纪念品跟踪对象并神奇地恢复它们的状态,你必须让对象自己意识到纪念品,它引入了耦合或使用反射来修改跟踪的引用的内部状态。基本上,您不需要将持久化状态反序列化为新对象,而是使用反射将先前存储的内部状态覆盖到跟踪的对象引用中。
小心使用WeakReference存储引用,否则你会发现自己有一个很好的内存泄漏的情况。