Autor Beitrag
RobAll
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 34



BeitragVerfasst: Fr 26.04.19 22:46 
Guten Abend,

in meinem letzten Beitrag wurde ein Problem gelöst, allerdings das Nächste eröffnet..

Aufgabe: Kopieren eines ObservableCollection Item (Datensatz einer DataGrid Row soll kopiert werden)
Problem: Das neue Objekt referenziert auf dem alten. -> _StammdatenList.Add(Datensatz) funktioniert aber der Alte und Neue Datensatz stehen in Relation;

Letzter Lösungsansatz:
ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
foreach (var item in (System.Collections.IEnumerable)Datensatz)
{
    ICloneable cloneable = item as ICloneable;
    if (cloneable != null)
    {
        _StammdatenList.Add(cloneable.Clone());
    }
}

"cloneable.Clone" erzeugt die Fehlermeldung:
Zitat:
Schweregrad Code Beschreibung Projekt Datei Zeile Unterdrückungszustand
Fehler CS1503 Argument "1": Konvertierung von "object" in "C.ViewModel.StammdatenViewModel" nicht möglich.

Nun komme ich nicht mehr weiter...

Bitte um Hilfe

Moderiert von user profile iconTh69: C#-Tags hinzugefügt
Moderiert von user profile iconTh69: Quote-Tags hinzugefügt
Ralf Jansen
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 4700
Erhaltene Danke: 991


VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
BeitragVerfasst: Sa 27.04.19 00:08 
Schau dir die Clone() Methode, sieh als was der Klon da zurückgegeben wird, überlege welchen Typ _StammdatenList.Add eigentlich erwartet und mach dann das passende.

Moderiert von user profile iconTh69: C#-Tags hinzugefügt
RobAll Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 34



BeitragVerfasst: Sa 27.04.19 12:37 
also die _StammdatenList ist vom Typ ObservableCollection, und das Objekt cloneable.Clone vom Typ ICloneable.

Jetzt muss ich cloneable.Clone in ObservableCollection konvertieren?

Ich habe schon getestet aber ich bekomme immer die Info.

"cloneable.Clone"
Zitat:
Fehler CS1503 Argument "1": Konvertierung von "object" in "C.ViewModel.StammdatenViewModel" nicht möglich.


Bitte nochmals um Hilfe, sitze schon den ganzen Vormittag..

ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
foreach (StammdatenViewModel item in (System.Collections.IEnumerable)_StammdatenList)
{
    if (item.ID == 1)
    {
        ICloneable cloneable = item as ICloneable;
                       
        _StammdatenList.Add(cloneable.Clone());
}


Moderiert von user profile iconTh69: C#-Tags hinzugefügt
Ralf Jansen
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 4700
Erhaltene Danke: 991


VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
BeitragVerfasst: Sa 27.04.19 12:57 
Zitat:
also die _StammdatenList ist vom Typ Observable Collection, und das Objekt cloneable.Clone vom Typ ICloneable.

Nein. Die clonable Variable is vom Typ ICloneable. Die Instanz auf die von dieser Variablen verwiesen wird wird irgendwas anders sein. cloneable.Clone() liefert dir einen Klon. Und wenn du dir das ICloneable Interface genauer ansehen würdest würdest du sehen das der Return Typ der Methode object ist. Der Compiler kann es also nicht besser wissen als das was die Definition der Interface Methode hergibt und wird von object aussgehen.

Zitat:
Fehler CS1503 Argument "1": Konvertierung von "object" in "C.ViewModel.StammdatenViewModel" nicht möglich.

Woher object kommt habe ich gerade erklärt. Deine StammdatenList ObservableCollection verwaltet scheinbar Instanzen vom Typ StammdatenViewModel. Die Add Methode wird also als Parameter nur Verweise des Typs StammdatenViewModel (oder Ableitungen davon) annehmen. object ist kein StammdatenViewModel also wird der Kompiler bei dem Add Aufruf streiken.

C# ist eine Typsichersprache und will Typkompatibilität schon zur Compilezeit sicherstellen und das kann es nicht für deinen Code. Wenn du es besser weißt, also du weißt was für ein Typ aus der Clone Methode rauskommt dann caste das Ergebnis der Methode auf diesen Typ (StammdatenViewModel) und übergebe das an Add.
RobAll Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 34



BeitragVerfasst: Sa 27.04.19 15:54 
Danke für die Info, aber ich bekomme keinen Lösungsansatz..
Th69
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Moderator
Beiträge: 4764
Erhaltene Danke: 1052

Win10
C#, C++ (VS 2017/19/22)
BeitragVerfasst: Sa 27.04.19 16:57 
Von welchem Typ soll denn überhaupt Datensatz sein? StammdatenViewModel?
Warum iterierst du dann darüber?

Möchtest du nicht einfach davon eine Kopie erstellen?
Also in etwa:
ausblenden C#-Quelltext
1:
2:
3:
var newItem = Datensatz.Clone() as StammdatenViewModel;
if (newItem != null)
    _StammdatenList.Add(newItem);
RobAll Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 34



BeitragVerfasst: Sa 27.04.19 20:41 
Hallo, das habe ich auch schon getestet,
allerdings fehlt mir die using-Direktive, ich konnte hierzu nichts finden
ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Windows;
using System.Windows.Data;
using System.Windows.Input;
using System.Data;

Zitat:
Fehler CS1061 "StammdatenViewModel" enthält keine Definition für "Clone", und es konnte keine Clone-Erweiterungsmethode gefunden werden, die ein erstes Argument vom Typ "StammdatenViewModel" akzeptiert (möglicherweise fehlt eine using-Direktive oder ein Assemblyverweis).

-> Mit dem ICloneable habe ich mich aus dem Netz verstrickt, als Anfänger verläuft man sich sehr schnell auf verschiedenen Wegen..

Moderiert von user profile iconTh69: C#-Tags hinzugefügt
Moderiert von user profile iconTh69: Quote-Tags hinzugefügt
Th69
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Moderator
Beiträge: 4764
Erhaltene Danke: 1052

Win10
C#, C++ (VS 2017/19/22)
BeitragVerfasst: So 28.04.19 09:43 
Die Clone-Methode (sowie das Hinzufügen des ICloneable-Interface) mußt du natürlich selber bei der Klasse implementieren.

Ich finde diese nicht-generische Schnittstelle sowie keine gute Lösung (eben wegen dem zusätzlichen Cast).

Du könntest auch einfach einen Konstruktor für das Kopieren bereitstellen:
ausblenden C#-Quelltext
1:
2:
3:
4:
public StammdatenViewModel(StammdatenViewModel other)
{
  // copy elements
}

Und dann einfach per new kopieren:
ausblenden C#-Quelltext
1:
var newItem = new StammdatenViewModel(Datensatz);					


Aber eigentlich solltest du doch ein darunterliegendes Modell haben, das kopiert wird und daraus dann ein neues VM-Objekt erzeugen.
Frühlingsrolle
Ehemaliges Mitglied
Erhaltene Danke: 1



BeitragVerfasst: So 28.04.19 15:13 
- Nachträglich durch die Entwickler-Ecke gelöscht -
Christian S.
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 20451
Erhaltene Danke: 2264

Win 10
C# (VS 2019)
BeitragVerfasst: So 28.04.19 23:30 
@Frühlingsrolle: Das verfehlt irgendwie das, was man mit dem klonen eines Objektes erreichen will, nämlich ein Kopie mit unterschiedlicher Referenz zu erzeugen. Original und Klon sind bei Dir das selbe (und nicht nur das gleiche) Objekt, dann kann ich auch einfach eine Zuweisung machen.

_________________
Zwei Worte werden Dir im Leben viele Türen öffnen - "ziehen" und "drücken".
Frühlingsrolle
Ehemaliges Mitglied
Erhaltene Danke: 1



BeitragVerfasst: Mo 29.04.19 00:48 
- Nachträglich durch die Entwickler-Ecke gelöscht -
Th69
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Moderator
Beiträge: 4764
Erhaltene Danke: 1052

Win10
C#, C++ (VS 2017/19/22)
BeitragVerfasst: Mo 29.04.19 09:13 
Sorry, aber so auch nicht:
- unnotiger Member _clone
- (dadurch auch) IDisposable unnötig

Außerdem ist das Beispiel mit einem string-Member schlecht gewählt, da dieser zwar eine Klasse (Referenz) ist, jedoch immutable!
Frühlingsrolle
Ehemaliges Mitglied
Erhaltene Danke: 1



BeitragVerfasst: Mo 29.04.19 09:29 
- Nachträglich durch die Entwickler-Ecke gelöscht -
RobAll Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 34



BeitragVerfasst: Mo 29.04.19 21:53 
Da gibt es nun viele Informationen von euch.

Welchen Weg soll ich denn nun als Anfänger verwenden, um das Objekt ohne Referenz zu kopieren/klonen?

Beispiel von Th69, hier benötige ich nun noch die Klasse Methode für Clone
ausblenden C#-Quelltext
1:
2:
3:
var newItem = Datensatz.Clone() as StammdatenViewModel;
if (newItem != null)
    _StammdatenList.Add(newItem);


Moderiert von user profile iconTh69: C#-Tags hinzugefügt
Th69
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Moderator
Beiträge: 4764
Erhaltene Danke: 1052

Win10
C#, C++ (VS 2017/19/22)
BeitragVerfasst: Di 30.04.19 08:28 
Das mußt du dann individuell ausprogrammieren (d.h. für alle Member einzeln) - Stichwort: Deep Copy

Aber besser als die Clone-Methode wäre es so, wie in meinem vorletzten Beitrag beschrieben!
RobAll Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 34



BeitragVerfasst: Mi 01.05.19 01:16 
Sorry, ich komme immer noch nicht weiter..
So viel gelesen, getestet.... seid dem 26.04
Ich will einen Datensatz im DataGrid kopieren und diesen danach ändern
ausblenden C#-Quelltext
1:
_StammdatenList.Add(Datensatz); // funktioniert, allerdings mit Relation					

Mein letzter Versuch.., mit euren anderen Informationen bin ich leider nicht klar gekommen.
ausblenden C#-Quelltext
1:
2:
StammdatenViewModel a = Datensatz , b ;
b = new StammdatenViewModel (a);

Zitat:
(a);
Fehler CS1503 Argument "1": Konvertierung von "C.ViewModel.StammdatenViewModel" in "C.Stammdaten" nicht möglich. ???

Bitte nochmals um Hilfe und um ein CodeBeispiel, bin Anfänger/Quereinsteiger

Danke Euch vorab nochmals!!

Moderiert von user profile iconTh69: C#-Tags hinzugefügt
Moderiert von user profile iconTh69: Quote-Tags hinzugefügt
Th69
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Moderator
Beiträge: 4764
Erhaltene Danke: 1052

Win10
C#, C++ (VS 2017/19/22)
BeitragVerfasst: Mi 01.05.19 09:04 
Das ist doch jetzt schon das 2. mal, daß du diesen Fehler (CS1503) erhältst.
Du scheinst Probleme mit dem Verständnis von Datentypen zu haben.

In deinem Fall hast du wohl einen Konstruktor
ausblenden C#-Quelltext
1:
public StammdatenViewModel(Stammdaten stammdaten)					

aber eben keinen (so wie ich oben schon geschrieben habe):
ausblenden C#-Quelltext
1:
public StammdatenViewModel(StammdatenViewModel stammdatenViewModel) // oder other (wie bei mir)					

Also mußt du entweder diesen ausimplementieren oder aber (so wie ich auch schon geschrieben habe) das Model (d.h. die Stammdaten) kopieren und dann die Kopie als Parameter an den Konstruktor übergeben.

Sorry, anders kann ich es dir nicht erklären. Vllt. solltest du noch mal ein Buch zu Datentypen und deren Benutzung sowie Umwandlung dazu lesen.

PS: Und bitte beim Posten demnächst selber die passenden Tags (C#, Quote etc.) benutzen.
RobAll Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 34



BeitragVerfasst: Do 02.05.19 23:35 
Leider referenzieren das kopierte und original Objekt im DataGrid immer noch. (Kopie und Original werden beim Editieren geändert)
Code:
ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
//Konstruktoraufruf mit Parameterübergabe
StammdatenViewModel Item = new StammdatenViewModel(Datensatz);
_StammdatenList.Add(Item);

// Kopierkonstruktor
public StammdatenViewModel(StammdatenViewModel Item)
{
    Einzelteilname = Item.Einzelteilname;
    Einzelteilnummer = Item.Einzelteilnummer;
    Einzelteilrevision = Item.Einzelteilrevision;
}


Moderiert von user profile iconTh69: C#-Tags hinzugefügt
Chiyoko
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 298
Erhaltene Danke: 8

Win 98, Win Xp, Win 10
C# / C (VS 2019)
BeitragVerfasst: Fr 03.05.19 09:05 
Hallo,

nutze bitte C# Tags für deinen Code. ( [ cs ] )

Um eine Instanz zu kopieren, gibt es mehrere Wege.
Zuerst mal gilt es zu unterscheiden, ob du Referenztypen oder Wertetyen in deiner Klasse hast.

Generell sind alle Klassen, abgesehen von einigen Ausnahmen (z.b. String), Referenztypen.
Wertetypen sind Structs, int, long, short usw.

Stell dir einen Bereich im Speicher vor, wo deine Klasse abgelegt wurde.
Erstellst du von dem Objekt eine neue Instanz, wird nur ein Pointer erstellt, der auf die Referenz verweist.
Das ist die sogenannte flache bzw. Schattenkopie. Du hast also ein weiteres Objekt erstellt, wo die
Instanzen in der Klasse immer auf das selbe Original verweisen.

Andernfalls brauchst du eine tiefe Kopie bzw. Deep Copy.
Von letzterem gibt es verschiedene Möglichkeiten.
Wenn du nur eine Klasse vergleichen willst, implementiere Equals, dann kann das Objekt auch Schattenkopie sein.

Ansonsten kannst du das Objekt in der Klasse serialisieren oder jede Property in der Klasse neu setzen.
Das geht am einfachsten mit einer Erweiterung.


ausblenden volle Höhe C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
//Serialisierung (Klasse benötigt das Attribut Serializeable
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);
 }
}

[Serializable]
public class SecondClass
{
    public int Id { get; }

    public string Quality { get; set; }

    public int HitQuality { get; set; }


    public override bool Equals(object obj)
    {
        var other = obj as SecondClass;
        if (Id == other?.Id) return true;

        return false;
    }

    public SecondClass(int hit, string qualy)
    {
        Id ++;
        Quality = qualy;
        HitQuality = hit;
    }
}

public class TestClass
{
    public string Quality { get; set; }

    public int HitQuality { get; set; }

    public List<SecondClass> ScList { get; } = new List<SecondClass>();

    public TestClass()
    {
        ScList.Add(new SecondClass(1"Test1"));
        ScList.Add(new SecondClass(2"Test2"));

        SecondClass s = ScList.FirstOrDefault();
        var deepCopy = DeepClone(s);
    }
}


Zuletzt bearbeitet von Chiyoko am Fr 03.05.19 10:09, insgesamt 2-mal bearbeitet
Th69
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Moderator
Beiträge: 4764
Erhaltene Danke: 1052

Win10
C#, C++ (VS 2017/19/22)
BeitragVerfasst: Fr 03.05.19 09:25 
@Chiyoko: Ich kann nicht erkennen, daß dein Code eine "Deep Copy" durchführt (auch deine Methode setzt nur die einzelnen Properties aus dem Original, d.h. führt nur eine "Shallow Copy" durch... - deine Klasse SecondClass ist aber auch ungeeignet, das zu demonstrieren).
Bei einer "Deep Copy" muß für jedes Referenztyp-Element ein neues Objekt (inklusive Unterobjekte) angelegt werden (d.h. getrennten Speicherbereich) - aber mit dem Stichwort hätte @RobAll ja auch schon lange im Internet suchen können.

PS: Auch String ist eine Klasse, d.h. ein Referenztyp, nur eben "immutable" implementiert!