![](/img/trans.png)
[英]The referenced project is a non self-contained executable. A non self-contained executable cannot be referenced by a self-contained executable
[英]Self-contained generic memento
亲爱的程序员,
对于引用在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);
}
}
}
额外信息
我的猜测是,我在做/理解有关List的某些错误。
我还尝试了Interlocked.Exchange,使用WeakReference来处理“ ref”,并将对象存储到CareTaker对象中(并将该CareTaker存储到List中),实现一些复制Property的事情...
而且...我只是看不到它。
我的预期结果将是PrestationInfo.Advance属性,该属性包含值2。
看来问题出在您对.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来存储引用,否则您会发现自己遇到了内存泄漏的情况。
Memento.Add需要一个ref参数修饰符来访问原始引用类型指针。
https://msdn.microsoft.com/en-us/library/14akc2c7.aspx?f=255&MSPPError=-2147217396
尝试这个:
更改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>
,并相应地调整代码
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.