[C#]Clonen van inherited objecten

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

  • Gwannoes
  • Registratie: Juni 2002
  • Laatst online: 25-08 21:23

Gwannoes

Solderen moet je leren

Topicstarter
Beetje vage titel, maar hier is mijn probleem:

Ik wil een aantal classes maken met public fields waar ik settings in opsla. Een aantal fields worden gedeeld door alle klassen, dus dacht ik: ik leid ze allemaal af van een basisklasse.

Voorbeeld: (Overigens is dit voorbeeld met eenvoudige types int en string, maar hier kunnen ook ingewikkelder types bij zitten...)
C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class BaseProperties : ICloneable
{
  public int a;
  public int b;

  public Object Clone()
  {
    return this.MemberwiseClone()
  }
}

public class Properties2 : BaseProperties, ICloneable
{
  public string c;
}

Hoe kan ik nu een Clone() functie aanmaken voor Properties2, die zowel a,b als c cloont?
Als ik een clone van BaseProperties heb en cast naar (Properties2), moet ik vervolgens zelf alle velden van Properties2 er nog bij gaan overzetten, da's ook niet helemaal de bedoeling...

by the way: ik werk met .NET 2.0

[ Voor 24% gewijzigd door Gwannoes op 13-01-2011 15:58 ]

Hmmz, hier komt dus m'n sig


Acties:
  • 0 Henk 'm!

  • EddoH
  • Registratie: Maart 2009
  • Niet online

EddoH

Backpfeifengesicht

Eh..als ik je bedoeling goed begrijp:

Klik

edit: volgens mij begreep ik je toch niet helemaal goed? Als je een object van type Properties2 wil Clonen moet je gewoon zorgen dat die z'n eigen Clone methode heeft natuurlijk...

[ Voor 42% gewijzigd door EddoH op 13-01-2011 15:59 ]


Acties:
  • 0 Henk 'm!

  • Gwannoes
  • Registratie: Juni 2002
  • Laatst online: 25-08 21:23

Gwannoes

Solderen moet je leren

Topicstarter
EddoH schreef op donderdag 13 januari 2011 @ 15:56:
Eh..als ik je bedoeling goed begrijp:

Klik

edit: volgens mij begreep ik je toch niet helemaal goed? Als je een object van type Properties2 wil Clonen moet je gewoon zorgen dat die z'n eigen Clone methode heeft natuurlijk...
Uiteraard moet die z'n eigen Clone methode hebben... Maar die Clone methode moet c clonen, maar ook a en b uit z'n base class. Voor die a en b zou ik liefst de Clone methode van BaseProperties gebruiken, maar dat kun je niet "samenvoegen" met een clone van Properties2.

Hmmz, hier komt dus m'n sig


Acties:
  • 0 Henk 'm!

  • RobIII
  • Registratie: December 2001
  • Niet online

RobIII

Admin Devschuur®

^ Romeinse Ⅲ ja!

(overleden)
Gwannoes schreef op donderdag 13 januari 2011 @ 16:03:
[...]

Uiteraard moet die z'n eigen Clone methode hebben... Maar die Clone methode moet c clonen, maar ook a en b uit z'n base class. Voor die a en b zou ik liefst de Clone methode van BaseProperties gebruiken, maar dat kun je niet "samenvoegen" met een clone van Properties2.
Tuurlijk wel. Gewoon c klonen en base.Clone() aanroepen.

There are only two hard problems in distributed systems: 2. Exactly-once delivery 1. Guaranteed order of messages 2. Exactly-once delivery.

Je eigen tweaker.me redirect

Over mij


Acties:
  • 0 Henk 'm!

  • Roxors
  • Registratie: April 2009
  • Laatst online: 17-09 12:59
Zoiets dus:

C#:
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
    public class BaseProperties
    {
        public int a;
        public int b;

        public BaseProperties CloneImpl()
        {
            return (BaseProperties) MemberwiseClone();
        }
    }

    public class Properties2 : BaseProperties, ICloneable
    {
        public string c;

        object ICloneable.Clone()
        {
            return CloneImpl();
        }

        public Properties2 Clone()
        {
            return (Properties2)CloneImpl();
        }
    }


En geen gedoe meer met casting in je aanroepende classen.

[ Voor 5% gewijzigd door Roxors op 13-01-2011 16:13 ]


Acties:
  • 0 Henk 'm!

  • Davio
  • Registratie: November 2007
  • Laatst online: 06-01 16:46
Gaat het niet automatisch goed als je een object hebt van Properties2 en daarop clone aanroept?

MemberwiseClone kopieert namelijk alle velden van het huidige object en in het geval van Properties2 zal hij dan toch de string meenemen?

De methode is immers door inheritance ook gedefinieerd voor Properties2.

Acties:
  • 0 Henk 'm!

  • Gwannoes
  • Registratie: Juni 2002
  • Laatst online: 25-08 21:23

Gwannoes

Solderen moet je leren

Topicstarter
RobIII schreef op donderdag 13 januari 2011 @ 16:07:
[...]

Tuurlijk wel. Gewoon c klonen en base.Clone() aanroepen.
Ja, voor een enkele string c is dat wel te doen... Maar als ik nou 50 fields in BaseProperties heb staan, en daar voor Properties2 nog eens 50 aan toevoeg... Dan wil je liever dat het "automagisch" gemerged wordt oid... Begrijp je?
Als het niet mogelijk is, zal ik wel moeten, maar ik hoop dat iemand ten minste begrijpt wat ik bedoel...
Davio schreef op donderdag 13 januari 2011 @ 16:27:
Gaat het niet automatisch goed als je een object hebt van Properties2 en daarop clone aanroept?

MemberwiseClone kopieert namelijk alle velden van het huidige object en in het geval van Properties2 zal hij dan toch de string meenemen?

De methode is immers door inheritance ook gedefinieerd voor Properties2.
hmmm, die zou dan ook string c meenemen? Zou kunnen... en dan voor meer complexe reference types die alsnog zelf clonen... Ga ik morgen proberen!

[ Voor 16% gewijzigd door Gwannoes op 14-01-2011 08:38 ]

Hmmz, hier komt dus m'n sig


Acties:
  • 0 Henk 'm!

  • Jeroen V
  • Registratie: Februari 2004
  • Laatst online: 16-09 21:23

Jeroen V

yadda yadda yadda

[b]Gwannoes schreef op donderdag 13 januari 2011 @ 17:04:hmmm, die zou dan ook string c meenemen? Zou kunnen... en dan voor meer complexe reference types die alsnog zelf clonen... Ga ik morgen proberen!
Ja, dit zou gewoon moeten werken, die c krijg je netjes mee als je een instantie van Properties2 zou clonen.

Let er met complexe types wel op dat die niet gecloned zullen worden, dat zal je toch echt zelf moeten doen. (volgens mij wordt er een pointer naar je complexe type gecloned, dus dat heeft als resultaat dat je uiteindelijk dezelfde instantie van je complexe type aan het wijzigen bent)

Acties:
  • 0 Henk 'm!

  • Gwannoes
  • Registratie: Juni 2002
  • Laatst online: 25-08 21:23

Gwannoes

Solderen moet je leren

Topicstarter
Davio schreef op donderdag 13 januari 2011 @ 16:27:
Gaat het niet automatisch goed als je een object hebt van Properties2 en daarop clone aanroept?

MemberwiseClone kopieert namelijk alle velden van het huidige object en in het geval van Properties2 zal hij dan toch de string meenemen?

De methode is immers door inheritance ook gedefinieerd voor Properties2.
Het werkt inderdaad. Zie experiment-code hieronder:
C#:
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
    class BaseClass
    {
        public int a;
        public Double b;
        public String c;

        public BaseClass Clone()
        {
            BaseClass clone = (BaseClass)this.MemberwiseClone();
            return clone;
        }
    }

    class DerivedClass : BaseClass
    {
        public ComplexType d;
        public Double e;
        
        public new DerivedClass Clone()
        {
            DerivedClass clone = (DerivedClass)base.Clone();
            clone.d = this.d.Clone();

            return clone;
        }
    }

    class ComplexType
    {
        public String ca;
        public int cb;

        public ComplexType Clone()
        {
            return (ComplexType)this.MemberwiseClone();
        }
    }

Ik had gedacht dat als ik binnen DerivedClass.Clone() base.Clone() aanroep, hij ook alleen zijn base-values zou clonen. Maar dat is dus niet waar, want ook DerivedClass.e wordt netjes gecloned.
En ik wist niet dat ik een instance van BaseClass zomaar kan casten naar een instance van DerivedClass.

Anyway: problem solved... Thanks!

Hmmz, hier komt dus m'n sig


Acties:
  • 0 Henk 'm!

  • Woy
  • Registratie: April 2000
  • Niet online

Woy

Moderator Devschuur®
Gwannoes schreef op vrijdag 14 januari 2011 @ 09:52:
[...]
En ik wist niet dat ik een instance van BaseClass zomaar kan casten naar een instance van DerivedClass.
Dat kan ook niet zomaar, maar alleen als BaseClass ook daadwerkelijk een DerivedClass is. Dat de MemberwiseClone aangeroepen word in BaseClass haalt niets uit, aangezien het type gewoon een DerivedClass is, en dus zal MemberwiseClone ook gewoon DerivedClass clonen.

“Build a man a fire, and he'll be warm for a day. Set a man on fire, and he'll be warm for the rest of his life.”


Acties:
  • 0 Henk 'm!

  • Gwannoes
  • Registratie: Juni 2002
  • Laatst online: 25-08 21:23

Gwannoes

Solderen moet je leren

Topicstarter
Overigens wel wazig dat een string, wat een reference type is, toch gewoon met z'n value gekopieerd wordt bij MemberwiseClone()...

Hmmz, hier komt dus m'n sig


Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 17-09 14:05

.oisyn

Moderator Devschuur®

Demotivational Speaker

Wat bedoel je nou precies :? De reference wordt gekopiëerd, er wordt geen nieuwe instantie aangemaakt. Maar goed, string.Clone() returnt ook gewoon 'this', dus zelfs bij een deep copy hou je dezelfde reference.

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


Acties:
  • 0 Henk 'm!

  • Gwannoes
  • Registratie: Juni 2002
  • Laatst online: 25-08 21:23

Gwannoes

Solderen moet je leren

Topicstarter
Correct me if I'm wrong... maar volgens mij is het niet waar wat je zegt. Als ik, in het voorbeeld hierboven, een Clone() aanroep op een instance van BaseClass, en ik verander de inhoud van string c, dan hebben mijn origineel en de clone een verschillende waarde van c.

Of... komt dat misschein doordat er bij het veranderen van de waarde een nieuwe reference naar een nieuw stuk memory wordt gemaakt...?Als ik:
C#:
1
BaseClassInstance.c = "bla";

doe, dan wordt "bla" zeker als een nieuwe instance gezien, met een nieuwe reference? Dus de String constructor aangeroepen? Dat zou de boel verklaren...

Hmmz, hier komt dus m'n sig


Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 17-09 14:05

.oisyn

Moderator Devschuur®

Demotivational Speaker

Je kan de inhoud van een string helemaal niet aanpassen. Als jij str = "bla" doet, dan ken je een nieuwe reference aan 'str' toe. Je wijzigt niet het string object waar 'str' eerst naar wees. En zo werken references altijd:
C#:
1
2
3
Person p = new Person("Henk");
Person p2 = p;  // p2 en p wijzen nu naar dezelfde persoon
p2 = new Person("Kees"); // p2 wijst nu naar Kees, p nog steeds naar Henk. Het is niet dat Henk nu aangepast is oid
doe, dan wordt "bla" zeker als een nieuwe instance gezien, met een nieuwe reference? Dus de String constructor aangeroepen?
Hoezo, "dus" de constructor aanroepen. Bij een toekenning van een reference wordt er helemaal geen constructor aangeroepen. Dat wordt pas gedaan als je new string(...) zou doen. Een string literal in je code (zoals "bla") is al geconstruct voor je code wordt uitgevoerd. De expressie "bla" levert dus gewoon direct een reference op naar een string met als inhoud "bla", en elke keer dat je code wordt uitgevoerd is die reference in de praktijk hetzelfde (binnen dezelfde sessie natuurlijk).

[ Voor 82% gewijzigd door .oisyn op 14-01-2011 12:19 ]

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


Acties:
  • 0 Henk 'm!

  • Gwannoes
  • Registratie: Juni 2002
  • Laatst online: 25-08 21:23

Gwannoes

Solderen moet je leren

Topicstarter
Ja klopt. Ik was alleen even misleid doordat ik niet expliciet een constructor aanroep bij [code=c#]BaseClassInstance.c = "bla"[/code]
.oisyn schreef op vrijdag 14 januari 2011 @ 12:08:
Hoezo, "dus" de constructor aanroepen. Bij een toekenning van een reference wordt er helemaal geen constructor aangeroepen. Dat wordt pas gedaan als je new string(...) zou doen. Een string literal in je code (zoals "bla") is al geconstruct voor je code wordt uitgevoerd. De expressie "bla" levert dus gewoon direct een reference op naar een string met als inhoud "bla", en elke keer dat je code wordt uitgevoerd is die reference in de praktijk hetzelfde.
Aha! Natuurlijk, de string staat in de programmacode, en heeft daarmee al een memory location...

[ Voor 71% gewijzigd door Gwannoes op 14-01-2011 12:16 ]

Hmmz, hier komt dus m'n sig


Acties:
  • 0 Henk 'm!

  • Woy
  • Registratie: April 2000
  • Niet online

Woy

Moderator Devschuur®
Verder is een string ook Immutable, als je 2 references naar dezelfde string hebt, is het niet mogelijk om op 1 van die references een wijziging te doen die je bij de 2e reference ook ziet.

C#:
1
2
3
4
5
6
Person p1 = new Person("Klaas");
Person p2 = p1;
p1.Name = "Piet";
Console.WriteLine( p2.Name ); //Piet
String s1 = "Klaas";
String s2 = s1;

Er bestaat geen String.Value o.i.d. die je kan assignen zodat beide refs aangepast worden. Alle wijzigingen leveren dus een nieuwe String op, en de andere references zullen dus naar de oude blijven wijzen.

Als je in dit geval dus een Person cloned, dan verwijzen beide Name properties misschien wel naar dezelfde string, maar het is niet zo dat je de Name van beide Person's in een keer aan kunt passen.

[ Voor 15% gewijzigd door Woy op 14-01-2011 12:49 ]

“Build a man a fire, and he'll be warm for a day. Set a man on fire, and he'll be warm for the rest of his life.”

Pagina: 1