Laden...

Values von Properties beim Clonen auf null prüfen

Erstellt von Glowhollow vor 5 Jahren Letzter Beitrag vor 5 Jahren 1.581 Views
G
Glowhollow Themenstarter:in
74 Beiträge seit 2018
vor 5 Jahren
Values von Properties beim Clonen auf null prüfen

Ja, der nervige hier 😉 bin wieder da 😄

Ich habe eine Copy Funktion.


public void CopyValues<T>(T target, T source)
        {
            Type t = typeof(T);

            var properties = t.GetProperties().Where(prop => prop.CanRead && prop.CanWrite);

            foreach (var prop in properties)
            {
                var value = prop.GetValue(source, null);
                if (value != null)
                    prop.SetValue(target, value, null);
            }
        }

Die Properties werden gut kopiert, kein thema. Jetzt habe ich aber Properties die 2 Subproperties beinhalten können.

In unserem Beispiel nennen wir sie jetzt content.link und content.value.

Jetzt ist es ja hier nicht zu unterscheiden ob content.link und content.value ungleich null sind.

Gibts dafür nen lösungsansatz ?

5.658 Beiträge seit 2006
vor 5 Jahren

Hi Glowhollow,

wieder einmal hast du das Rad neu erfunden und eine Methode geschrieben, die es bereits im Framework gibt: Object.MemberwiseClone.

Wenn ich deine Frage jetzt richtig verstehe (was wirklich nicht leicht ist), dann willst du vermutlich eine "Deep Copy"-Variante deiner Implementierung. Dazu mußt du Rekursion verwenden.

Vor allem aber hilft es bei der Umsetzung, sich vorher zu informieren, was es gibt, und wie es andere Entwickler umsetzen. Du kannst davon ausgehen, daß du nicht der erste Entwickler auf der Welt bist, der Objekte kopieren oder etwas ungewöhnliche JSON-Dateien parsen will. Ein paar Minuten im Internet recherchieren, kann dir viel Zeit sparen, Sachen zu implementieren, die es bereits gibt. Oder auch: "Weeks of coding can save you hours of planning."

Siehe auch: [Tipp] Schau in die Doku! - Möglichkeiten der Informationsgewinnung

Weeks of programming can save you hours of planning

78 Beiträge seit 2016
vor 5 Jahren

Die MSDN beschreibt dies in den Remarks von MemberwiseClone:

Dein MemberwiseClone führt ein "shallow copy" durch.

Möchtest du ein DeepCopy, dann gibt es da viele Wege (z.B. durch Serialisierung).
Siehe dazu:

https://docs.microsoft.com/en-us/dotnet/api/system.object.memberwiseclone?redirectedfrom=MSDN&view=netframework-4.7.2#remarks

http://dotnet-paderborn.azurewebsites.net/

5.658 Beiträge seit 2006
vor 5 Jahren

z.B. durch Serialisierung

Serialisierung will er ja gerade selbst implementieren

Weeks of programming can save you hours of planning

78 Beiträge seit 2016
vor 5 Jahren

z.B. durch Serialisierung

Serialisierung will er ja gerade
>
){gray}

@MrSparkle: Oh ja hast ja recht 😃. Das man "Serialisierung" nicht selber implementiert, wurde ja schon diskutiert. Der Rest des MSDN-Artikels wird Glowhollow sicherlich weiter bringen.

http://dotnet-paderborn.azurewebsites.net/

T
2.223 Beiträge seit 2008
vor 5 Jahren

Wen du nicht, wie von MrSparkle vermutet gegen Serialisierung abgeneigt bist, kannst du dies mit dem Serializable Attribute und einer einfachen Copy Methode umsetze.

Bsp:


public static T DeepClone<T>(T obj)
{
	using (var ms = new MemoryStream())
	{
		var formatter = new BinaryFormatter();
		formatter.Serialize(ms, obj);
		ms.Position = 0;

		return (T) formatter.Deserialize(ms);
	}
}

Da musst du dich überhaupt nicht um die ganzen Probleme mit einer händischen Lösung rumschlagen ud dürftest alleine damit schon zich Stunden an Zeit/Arbeit einsparen.

Falls du aber auch hier wieder, entgegen jeder Empfehlung, an einer eigenen Lösung festhalten willst, wirst du wohl oder über nicht um eine rekursive Lösung kommen.
Hier musst du eben über alle Ebene von Objekten laufe.
Also Listen/Arrays etc. was eben ein Container für Objekte sein kann und musst diese dann kopieren.

Aber ganz ehrlich, die Arbeit kannst du dir mit einfachen .NET Bordmitteln sparen.
Es gibt einfach keinen rationalen Grund auch hier wieder auf einfache Bordmittel, die genau dein Vorhabe abdecken, zu verzichten.

T-Virus

Developer, Developer, Developer, Developer....

99 little bugs in the code, 99 little bugs. Take one down, patch it around, 117 little bugs in the code.

G
Glowhollow Themenstarter:in
74 Beiträge seit 2018
vor 5 Jahren

Machmal denke ich echt, ich spreche eine andere Sprache 😃.

Nun, ich bin ja fast fertig mit dem Deserializer.

Aber, ich habe noch folgendes Problem. Achtung Wall of Text.

Die CopyFunktion, kopiert alles so wie ich es brauche, nicht rekursiv, das ist hier auch nicht notwendig. Das einzige was ich jetzt noch zum Abschluss brauche ist es zu prüfen, ob beim Deserialisieren (was in kleinen schritten passiert), Werte vorhanden sind.

So soll im Target, werte stehen, die von der Source kopiert werden. Richtig. Die Source sind aber nur elemente, werden aber jedoch komplett in der ganzen bandbreite deserialisiert. Das heißt, das ich im Target nur die Werte haben möchte, die auch deserialisiert sind. Da Source, aber abgesehen von einem einzelnen Restschritt, jeweils nur 1 Wert drin steht. Ist es so, das die anderen Werte auf null sind.

Diese sollen nicht kopiert werden. Das macht die Copy Funktion aber auch.

Jetzt ist es aber so, das der Bereich, in dem es zu einem Datensatz, mehrere werte gibt. In diesem fall, z.bsp. content.link und content.value, ist ja content gesetzt. jedoch sind die werte link und value auf null.

Jetzt erkennt die Copy Funktion das, sieht, content ist nicht null, und kopiert fröhlich drauf los und überschreibt mir die hart erarbeiteten Ergebnisse.

Das möchte ich verhindern. Am liebsten wäre mir eine if abfrage mit der ich prüfen kann, ob .... . link und .... value (es gibt da n ganzen satz von) jeweils null sind.

Ich würde ja gerne sowas in c#-konformer Syntax realisieren.

if (value != null && value.category.subcategory == null)

Aber irgendwie finde ich nicht die passenden Worte für.

G
Glowhollow Themenstarter:in
74 Beiträge seit 2018
vor 5 Jahren
 public void CopyValues<T>(ref T target, T source)
        {
            Type t = source.GetType();

            var properties = t.GetProperties().Where(prop => prop.CanRead && prop.CanWrite);

            foreach (var prop in properties)
            {
                if (prop.PropertyType.IsValueType || prop.PropertyType == typeof(string))
                {
                    var value = prop.GetValue(source, null);
                    if (value != null)
                    {
                        prop.SetValue(target, value, null);
                    }
                }
                else
                {
                    var sourceValue = prop.GetValue(source, null);
                    var targetValue = prop.GetValue(target, null);

                    if (targetValue == null)
                    {
                        targetValue = Activator.CreateInstance(sourceValue.GetType());
                    }

                    CopyValues(ref targetValue, sourceValue);

                    prop.SetValue(target, targetValue);
                }
            }
        }

das wars. Viel Spass mit dem Code.

78 Beiträge seit 2016
vor 5 Jahren

Aber das ist doch -Ansatzweise- sowas wie DeepCopy geworden.
Somit auch das was MrSparkle dir vorgeschlagen hat.

Nachtrag:
Ich hab das jetzt nicht im Compiler geprüft, aber führt

CopyValues(ref targetValue, sourceValue);

nicht zu

CopyValues<object>(ref targetValue, sourceValue);

somit zu einem falschen ...

Type t = source.GetType();

http://dotnet-paderborn.azurewebsites.net/