Wanneer wordt een C#-waarde/-object gekopieerd en wanneer wordt de verwijzing gekopieerd?

Ik krijg steeds weer hetzelfde probleem waar een object waarnaar ik wil verwijzen wordt gekopieerd of waar wordt verwezen naar een object dat ik wil kopiëren. Dit gebeurt als ik de operator = gebruik.

Bijvoorbeeld, als ik het object naar een ander formulier stuur, bijv.:

SomeForm myForm = new SomeForm();
SomeObject myObject = new SomeObject();
myForm.formObject = myObject;

…en vervolgens het object in het formulier wijzigt, wordt het oorspronkelijke object niet gewijzigd. Het is alsof het object is gekopieerd en er niet naar wordt verwezen. Maar als ik dit doe:

SomeObject myObject = new SomeObject();
SomeObject anotherObject = new SomeObject();
anotherObject = myObject;

…en pas vervolgens anotherObjectaan, myObjectwordt ook aangepast.

Het meest verzwarende geval is wanneer ik een van mijn gedefinieerde objecten probeer te klonen:

public class SomeObject
{
    double value1, value2;
    //default constructor here
    public SomeObject(val1, val2)
    {
        value1 = val1;
        value2 = val2;
    }
    public void Clone(SomeObject thingToCopy)
    {
        this.value1 = thingToCopy.value1;
        this.value2 = thingToCopy.value2;
    }
}

wanneer ik dit doe…

SomeObject obj1 = new SomeObject(1, 2);
SomeObject obj2 = new SomeObject();
obj2.Clone(obj1);

Er wordt verwezen naar

obj1en alle wijzigingen aan obj2veranderen obj1.

Systeemobjecten zoals int, double, string, enz. lijken altijd te worden gekopieerd, behalve in het geval van de bovenstaande kloonmethode.

Mijn vraag is, zonder rekening te houden met het gebruik van het sleutelwoord refin functies, wanneer wordt een object gekopieerd en wanneer wordt er in elk geval naar een object verwezen (dwz bij het passeren naar functies, bij het instellen als andere objecten (zoals de eerste twee bovenstaande voorbeelden), bij het kopiëren van lidvariabelen zoals het derde voorbeeld, enz.)?


Antwoord 1, autoriteit 100%

Het is moeilijk om dit soort vragen precies te beantwoorden zonder heel veel tijd te besteden aan het zorgvuldig kiezen van uw woorden.

Ik heb dit gedaan in een aantal artikelen die u wellicht nuttig vindt:

Dat wil natuurlijk niet zeggen dat de artikelen perfect zijn – verre van dat – maar ik heb geprobeerd zo duidelijk mogelijk te zijn.

Ik denk dat een belangrijk ding is om de twee concepten (parameter doorgeven en referentie versus waardetypes) in je hoofd te scheiden.

Om naar uw specifieke voorbeelden te kijken:

SomeForm myForm = new SomeForm();
SomeObject myObject = new SomeObject();
myForm.formObject = myObject;

Dit betekent dat myForm.formObjecten myObjectverwijzen naar hetzelfde exemplaar van SomeObject– zoals twee mensen met aparte stukjes papier, met elk met hetzelfde adres erop geschreven. Als je naar het adres op het ene vel papier gaat en het huis rood schildert, ga dan naar het adres op het tweede vel papier, je ziet een rood huis.

Het is niet duidelijk wat je bedoelt met “en pas dan het object in het formulier aan”, omdat het type dat je hebt opgegeven onveranderlijk is. Er is geen manier om het object zelf te wijzigen. U kunt myForm.formObjectwijzigen om naar een andere instantie van SomeObjectte verwijzen, maar dat is hetzelfde als het adres op een stuk papier krabbelen en in plaats daarvan een ander adres erop schrijven. Dat verandert niets aan wat er op het andere stuk papier staat.

Als u een kort maar compleetprogramma zou kunnen bieden waarvan u het gedrag niet begrijpt (idealiter een consoletoepassing, om de zaken korter en eenvoudiger te houden), zou het gemakkelijker zijn om over dingen concreet te praten voorwaarden.


Antwoord 2, autoriteit 14%

Hallo Mike
Alle objecten, die zijn afgeleid van ValueType, zoals struct of andere primitieve typen, zijn waardetypen. Dat betekent dat ze worden gekopieerd wanneer u ze aan een variabele toewijst of als methodeparameter doorgeeft. Andere typen zijn referentietypen, wat betekent dat, wanneer u een referentietype aan een variabele toewijst, niet de waarde, maar het adres in de geheugenruimte aan de variabele wordt toegewezen.
Houd er ook rekening mee dat u een waardetype als referentie kunt doorgeven met behulp van het ref-sleutelwoord. Hier is de syntaxis

public void MyMethod(ref int a) { a = 25 }
int i = 20;
MyMethod(ref i); //Now i get's updated to 25.

Hopelijk helpt het 🙂


Antwoord 3, autoriteit 2%

Met betrekking tot het klonen van uw objecten, als de waarden die u van het ene object naar het andere kopieert, referentietypen zijn, heeft elke wijziging aan die waarden in het oorspronkelijke object invloed op de waarden in het gekopieerde object (aangezien het slechts verwijzingen naar hetzelfde zijn) voorwerp)

Als u een object moet klonen dat eigenschappen heeft die referentietypen zijn, moet u deze typen kloonbaar maken of er een handmatige kopie van maken door indien nodig nieuwe instanties te instantiëren.

Overweeg het gebruik van de IClonable-interface, hoewel dit niet het geval is de beste oplossingen imho.

Other episodes