Не получается полностью клонировать лист с ссылочными объектами через рефлексию
Класс Part
является составной частью класса Tablet
в виде List<Part>
public class Part
{
public string Name { get; init; } = string.Empty;
public TableType Type { get; init; }
public double Value { get; set; }
public Part() { }
public Part(TableType type, double value)
{
Name = type.ToString();
Type = type;
Value = value;
}
public override string ToString()
=> $"Type: {Type}; Value: {Value}";
}
public class Tablet
{
public string Name { get; set; } = string.Empty;
public int TotalSlots { get; set; }
public List<Part> Parts { get; set; } = new();
public Tablet() { }
public Tablet(string name, TableType sizeType, double size,
TableType smthElse, double smthElseVal)
{
Name = name;
Parts.Add(new()
{
Name = sizeType.ToString(),
Type = sizeType,
Value = size
});
Parts.Add(new()
{
Name = smthElse.ToString(),
Type = smthElse,
Value = smthElseVal
});
}
}
У меня не получается сделать полную копию изначальной "базы данных" tabletDB
так, чтобы в дальнейшем ссылочные данные Parts
не менялись одновременно у разных объектов класса Tablet
Это можно легко исправить, если для каждого нового объекта Tablet
напрямую копировать List<Tablet> tabletDB
под новым имененем, но я хочу оставить одну базу данных List<Tablet> tabletDB
и в конструкторе класса клонировать эту базу.
List<Tablet> tabletDB = new()
{
new Tablet("Test", TableType.Square, 10, TableType.Rectangle, 10),
new Tablet("Test3", TableType.Square, 100, TableType.Rectangle, 100)
};
var tabletCopy = tabletDB.CloneList();
foreach (var partsOriginal in tabletDB)
{
foreach (var partOriginal in partsOriginal.Parts)
{
foreach (var partsCloned in tabletCopy)
{
foreach (var partCloned in partsCloned.Parts)
{
if (ReferenceEquals(partOriginal, partCloned))
{
Console.WriteLine($"Clone:\n\t {partCloned}" +
$"\nOriginal:\n\t {partOriginal}" +
$"\n\nSame reference!!!\n");
}
}
}
}
}
Clone:
Type: Square; Value: 10
Original:
Type: Square; Value: 10
Same reference!!!
Clone:
Type: Rectangle; Value: 10
Original:
Type: Rectangle; Value: 10
Same reference!!!
Clone:
Type: Square; Value: 100
Original:
Type: Square; Value: 100
Same reference!!!
Clone:
Type: Rectangle; Value: 100
Original:
Type: Rectangle; Value: 100
Same reference!!!
Вот метод с рефлексией, почему-то лист с вложенным классом не клонируется полностью.
public static List<T> CloneList<T>(this List<T> listToClone)
{
Type listType = listToClone.GetType();
Type elementType = listType.GetGenericArguments()[0];
List<T> listCopy = new();
foreach (T item in listToClone)
{
object itemCopy = Activator.CreateInstance(elementType)!;
foreach (PropertyInfo property in elementType.GetProperties())
{
elementType
.GetProperty(property.Name)
?.SetValue(itemCopy, property.GetValue(item));
}
listCopy.Add((T)itemCopy);
}
return listCopy;
}
Update 3/30/2023
Проблему решил заменой рефлексии на сериализацию:
string jsonString = JsonSerializer.Serialize(tabletDB);
var tabletDatabseFromJson = JsonSerializer.Deserialize<List<Tablet>>(jsonString);
Источник: Stack Overflow на русском