[英]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.