今天我在C#中使用引用时遇到了问题。我的用例如下:我在winform-application中有一个全局配置对象。打开设置屏幕时,对象的设置部分会被深度克隆。单击保存按钮时,元素应保存回原始参考。这不像我最初的预期那样有效。
我准备了一个网络小提琴,让你看一下这个问题。如果有人知道解决这个问题的方法,我非常感谢你的意见。我很感谢指出我的修正(我确信有人以更清洁的方式解决了这个问题)。
1)我们有一个全局可用的静态对象结构
2)在某个时间点,该结构的一部分应该从对象结构中脱离
3)将对已删除的部分进行编辑
4)稍后,应将MAYBE部分重新附加到对象结构中的原始引用
我是一名前端开发人员,很难用文字表达我的问题,所以看看我的代码:
https://dotnetfiddle.net/qzJqC4
---对于来自遥远未来的读者来说,链接已成为过去---
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.Serialization.Formatters.Binary;
namespace DemoCloneAndReattach
{
[Serializable]
public class DogFamily
{
public DogFamily()
{
PrettyDogs = new List<PrettyDog>();
}
public List<PrettyDog> PrettyDogs { get; set; }
}
[Serializable]
public class PrettyDog
{
public string Name { get; set; }
public int NumberOfEars { get; set; }
}
public class Program
{
public static void Main(string[] args)
{
// Note: The WriteLines will help you to validate the correctness of the solution. Thanks a lot!
// Setting up
DogFamily dogFamily = new DogFamily();
dogFamily.PrettyDogs.Add(new PrettyDog() { Name = "OriginalDog", NumberOfEars = 2 });
// Getting the dog with the name "OriginalDog"
PrettyDog originalDog = dogFamily.PrettyDogs.FirstOrDefault(o => o.Name == "OriginalDog");
originalDog.NumberOfEars = 3;
Console.WriteLine("originalDog has NumberOfEars (expected 3): " + originalDog.NumberOfEars);
// Checking if the originalDog in the List has the value updated (from 2 to 3). It does.
PrettyDog checkDogOne = dogFamily.PrettyDogs.FirstOrDefault(o => o.Name == "OriginalDog");
Console.WriteLine();
Console.WriteLine("checkDogOne has NumberOfEars (expected 3): " + checkDogOne.NumberOfEars);
// Now creating a deep-clone of the originalDog (this will result in a brand new object, not related to the DogFamily in any way)
PrettyDog clonedDog = DeepClone<PrettyDog>(originalDog);
// Doing something that should not YET be written to the DogFamily-reference tree.
clonedDog.NumberOfEars = 7;
// Checking if the clonedDog has not the same reference as the originalDog. As expected, it hasn't.
Console.WriteLine();
Console.WriteLine("clonedDog has NumberOfEars (expected 7): " + clonedDog.NumberOfEars);
Console.WriteLine("originalDog still has NumberOfEars (expected 3): " + originalDog.NumberOfEars);
// I want the behavior below, but automated (some kind of reverse-matching or -reattaching-logic to the reference of originalDog):
originalDog.Name = clonedDog.Name;
originalDog.NumberOfEars = clonedDog.NumberOfEars;
// Maybe the call to the solution would look like this:
// Reattach<PrettyDog>(originalDog, clonedDog);
Console.WriteLine();
Console.WriteLine("originalDog now has NumberOfEars (expected 7): " + originalDog.NumberOfEars);
Console.WriteLine("clonedDog has still NumberOfEars (expected 7): " + clonedDog.NumberOfEars);
// Checking if the reference is set correctly (not only the originalDog-reference but the whole reference-tree)
PrettyDog checkDogTwo = dogFamily.PrettyDogs.FirstOrDefault(o => o.Name == "OriginalDog");
Console.WriteLine();
Console.WriteLine("checkDogTwo has NumberOfEars (expected 7 - this is the tricky one): " + checkDogTwo.NumberOfEars);
}
public static T DeepClone<T>(T obj)
{
if (obj == null) return default(T);
using (var ms = new MemoryStream())
{
var formatter = new BinaryFormatter();
formatter.Serialize(ms, obj);
ms.Position = 0;
return (T)formatter.Deserialize(ms);
}
}
public static void Reattach<T>(T original, T clone)
{
// Logic for replacing the original with the clone without damaging the reference-tree
}
}
}