Beim Deep Cloning geht es um das Kopieren Staat . Für .net
Staat bedeutet Felder .
Nehmen wir an, man hat eine Hierarchie:
static class RandomHelper
{
private static readonly Random random = new Random();
public static int Next(int maxValue) => random.Next(maxValue);
}
class A
{
private readonly int random = RandomHelper.Next(100);
public override string ToString() => $"{typeof(A).Name}.{nameof(random)} = {random}";
}
class B : A
{
private readonly int random = RandomHelper.Next(100);
public override string ToString() => $"{typeof(B).Name}.{nameof(random)} = {random} {base.ToString()}";
}
class C : B
{
private readonly int random = RandomHelper.Next(100);
public override string ToString() => $"{typeof(C).Name}.{nameof(random)} = {random} {base.ToString()}";
}
Das Klonen kann durchgeführt werden:
static class DeepCloneExtension
{
// consider instance fields, both public and non-public
private static readonly BindingFlags bindingFlags =
BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
public static T DeepClone<T>(this T obj) where T : new()
{
var type = obj.GetType();
var result = (T)Activator.CreateInstance(type);
do
// copy all fields
foreach (var field in type.GetFields(bindingFlags))
field.SetValue(result, field.GetValue(obj));
// for every level of hierarchy
while ((type = type.BaseType) != typeof(object));
return result;
}
}
Demo1 :
Console.WriteLine(new C());
Console.WriteLine(new C());
var c = new C();
Console.WriteLine($"{Environment.NewLine}Image: {c}{Environment.NewLine}");
Console.WriteLine(new C());
Console.WriteLine(new C());
Console.WriteLine($"{Environment.NewLine}Clone: {c.DeepClone()}{Environment.NewLine}");
Console.WriteLine(new C());
Console.WriteLine(new C());
Ergebnis:
C.random = 92 B.random = 66 A.random = 71
C.random = 36 B.random = 64 A.random = 17
Image: C.random = 96 B.random = 18 A.random = 46
C.random = 60 B.random = 7 A.random = 37
C.random = 78 B.random = 11 A.random = 18
Clone: C.random = 96 B.random = 18 A.random = 46
C.random = 33 B.random = 63 A.random = 38
C.random = 4 B.random = 5 A.random = 79
Beachten Sie, dass alle neuen Objekte zufällige Werte für random
Feld, sondern clone
entspricht genau dem image
Demo2 :
class D
{
public event EventHandler Event;
public void RaiseEvent() => Event?.Invoke(this, EventArgs.Empty);
}
// ...
var image = new D();
Console.WriteLine($"Created obj #{image.GetHashCode()}");
image.Event += (sender, e) => Console.WriteLine($"Event from obj #{sender.GetHashCode()}");
Console.WriteLine($"Subscribed to event of obj #{image.GetHashCode()}");
image.RaiseEvent();
image.RaiseEvent();
var clone = image.DeepClone();
Console.WriteLine($"obj #{image.GetHashCode()} cloned to obj #{clone.GetHashCode()}");
clone.RaiseEvent();
image.RaiseEvent();
Ergebnis:
Created obj #46104728
Subscribed to event of obj #46104728
Event from obj #46104728
Event from obj #46104728
obj #46104728 cloned to obj #12289376
Event from obj #12289376
Event from obj #46104728
Beachten Sie, dass das Backing-Feld des Ereignisses ebenfalls kopiert wird und der Client auch das Ereignis des Klons abonniert hat.
112 Stimmen
Kann nützlich sein: "Warum ist das Kopieren eines Objekts eine schreckliche Sache?" agiledeveloper.com/articles/cloning072002.htm
2 Stimmen
stackoverflow.com/questions/8025890/ Eine andere Lösung...
28 Stimmen
Werfen Sie einen Blick auf AutoMapper
4 Stimmen
Deine Lösung ist viel komplexer, ich habe mich beim Lesen verlaufen... hehehe. Ich verwende eine DeepClone-Schnittstelle. public interface IDeepCloneable<T> { T DeepClone(); }
0 Stimmen
@Pedro77: Ein Anliegen, das ich habe
IDeepCloneable
ist, dass nicht alle Sammlungen von Verweisen auf Dinge, die tief geklont werden können, geklont werden sollten; das richtige Verhalten beim Klonen einerList<T>
hängt nicht nur vonT
sondern auch nach dem Zweck der Listen. Wenn keines der Elemente in den Listen jemals etwas ausgesetzt sein wird, das sie verändern könnte, wäre es besser, die Verweise direkt zu kopieren, selbst wenn die Elemente innerhalb der Listen geklont werden könnten.0 Stimmen
Diese Frage wird auch hier beantwortet stackoverflow.com/q/129389/235715
4 Stimmen
@Pedro77 -- Interessanterweise heißt es in dem Artikel am Ende, dass man eine
clone
Methode auf die Klasse anwenden und dann einen internen, privaten Konstruktor aufrufen, der anthis
. Kopieren ist also schrecklich [sic], aber sorgfältiges Kopieren (und der Artikel ist definitiv lesenswert) ist es nicht. ;^)0 Stimmen
Wenn Sie dies benötigen, haben Sie vielleicht eine falsche Implementierung. Und wenn Sie Dependency Injection verwenden, macht es überhaupt keinen Sinn.
0 Stimmen
Letztendlich sind diese Frage und alle Antworten ungefähr so nützlich wie "Wie programmiere ich eine Klasse?" Es gibt viele Antworten, aber es gibt keine einzige richtige Antwort, trotz Abstimmungen. Das heißt NICHT, dass keine Antwort nützlich ist oder dass die Frage nicht sinnvoll ist, aber man sollte sich vor polarisierenden Antworten hüten. Das größte Defizit ist hier die Betonung der Bereitstellung einer detaillierten Dokumentation und der Verantwortung des Benutzers/Implementierers einer Klasse für das Verständnis der Details jeder Kopieroperation.
0 Stimmen
Warum nicht einfach eine neue Instanz davon besorgen? Oder wenn Sie ein Objekt kopieren wollen, das Sie geändert haben, anstatt es nur zu instanziieren, können Sie auch eine Methode erstellen, die all das tut, und diese Methode einfach zweimal aufrufen.
0 Stimmen
Rufen Sie die MemberwiseClone-Methode auf, um eine oberflächliche Kopie eines Objekts zu erstellen, und weisen Sie dann allen Eigenschaften oder Feldern, deren Werte Referenztypen sind, neue Objekte zu, deren Werte mit denen des Originalobjekts übereinstimmen. Die DeepCopy-Methode im Beispiel veranschaulicht diesen Ansatz. msdn.microsoft.com/de-us/library/
0 Stimmen
Prüfen Sie dies Antwort : stackoverflow.com/a/52097307/4707576 über: Klonen von Objekten ohne Serialisierung