この問題についてさらに考えた結果、少なくとも小規模な実装では、オブジェクト自体を置き換えることなくオブジェクトのフィールドとプロパティの値をコピーする「値によるディープ コピー」メソッドを作成することが最善の方法であるという結論に達しました (そのため、編集されたオブジェクトへの参照は、データが復元されてもそのまま残ります)。
この目的のために、次の拡張メソッドを作成しました。
public static void CopyDataTo(this Object source, Object target) {
// Recurse into lists
if (source is IList) {
var a = 0;
foreach (var item in (IList)source) {
if (a >= ((IList)target).Count) {
var type = item.GetType();
var assembly = Assembly.GetAssembly(type);
var newItem = assembly.CreateInstance(type.FullName);
((IList)target).Add(newItem);
}
item.CopyDataTo(((IList)target)[a]);
a++;
}
while (a < ((IList)target).Count) {
((IList)target).RemoveAt(a);
}
}
// Copy over fields
foreach (var field in source.GetType().GetFields())
field.SetValue(target, field.GetValue(source));
// Copy properties
foreach (var property in source.GetType().GetProperties().Where(
property => property.CanWrite && !property.GetMethod.GetParameters().Any()))
{
property.SetValue(target, property.GetValue(source));
}
}
これは特効薬ではありません。同じ型のオブジェクトでのみ機能し、リスト項目にはパラメーターのないコンストラクターが必要であり、再帰の深さを制御する方法はありません。さらに、長期的またはより複雑なシナリオでテストする機会はまだありませんが、これまでのところ、必要なこと (オブジェクト間で値をコピーする) を行い、単純なバックアップ/復元シナリオに使用できます。
var backup = new TypeOfVariableToEdit();
data.CopyDataTo(backup);
var clickedOK = RunDataEditor(data);
if (!clickedOK)
backup.CopyDataTo(data);