[C#] Hoe zit het nou precies met... References ?

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

  • Wilde
  • Registratie: December 2000
  • Niet online
Ik ben tijdens mijn opleiding veel in Java geprogrammeerd. als je daar een = operator gebruikt wordt een nieuwe verwijzing gelegd naar het object. Bijvoorbeeld:

object o1
object o2

o2 = 01;

Nu zijn o1 en o2 gelijk (ze wijzen naar hetzelfde objct).

Ik ben sinds een paar maanden in C# begonnen en merk dat het hier anders werkt. Om een referentie naar een bestaand object in de aanroep van een methode mee te geven gebruik je het REF(of out, maar dat terzijde) keyword. Maar hoe zit het nu met het java voorbeeld in het begin van me'n post ?

Ik heb namelijk onderstaande klasse:

code:
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
   public partial class Imagemasking_window : Form
    {
        //class vars:
        Image _img;
        Boolean cancelchanges = true;


        public Imagemasking_window(ref Image img)
        {
            InitializeComponent();
            _img = img
            pictureBox1.Image = _img;
        }

        private void button1_Click(object sender, EventArgs e)
        {
            cancelchanges = false;
            this.Close();
        }

        private void Imagemasking_window_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (!cancelchanges)
            {
                _img = pictureBox1.Image;
            }
            else
            {
                _img = null;
            }
        }
    }


Deze klasse krijgt in de constructor een referentie naar een Image object mee. Als de boolean cancelchanges true wordt(valt even buiten het voorbeeldje) wordt _img op null gezet.

Het probleem hierin is is dat _img (de klassevariable) in dit voorbeeld een kopie wordt van de in de constructor opgegeven img. Het principe in deze klasse werkt dus niet. Hierdoor weet de aanroepende instantie nooit dat "zijn" image op null wordt gezet.

Ik hoop dat ik een beetje duidelijk over kom. zo niet zal ik eea proberen te verduidelijken.

Specs: 9800X3D, RTX 5090, 64GB, VR: Pimax Crystal-Light


Acties:
  • 0 Henk 'm!

  • Janoz
  • Registratie: Oktober 2000
  • Laatst online: 16-09 09:15

Janoz

Moderator Devschuur®

!litemod

Afaik werkt dat in java ook niet. Het is niet alsof bij een toekenning de objecten 'gebind' worden. Door null toe te kennen aan _img verander je alleen waar _img naar verwijst. 'img' wijst nog steeds naar het originele object.

Ken Thompson's famous line from V6 UNIX is equaly applicable to this post:
'You are not expected to understand this'


Acties:
  • 0 Henk 'm!

  • H!GHGuY
  • Registratie: December 2002
  • Niet online

H!GHGuY

Try and take over the world...

Java references zijn in gebruik gelijk aan C# references.

het 'ref' wat jij aanhaalt is nog iets anders. Deze laat namelijk toe om de reference 'by reference' door te geven, zodat binnen de methode de referentie van buiten de methode aangepast wordt.

In C++ pointer-speak zou je kunnen stellen:
- Java/C# references zijn equivalent aan pointers: void functie(object* o)
- C# 'ref' is equivalent aan pointer byref doorgeven: void functie(object* &o) of void functie(object** o)

in memory:
Java/C# references: reference ---> object
'ref': reference -----> references ---> object

Bovendien heeft Java zo'n ref niet.

[ Voor 3% gewijzigd door H!GHGuY op 22-07-2008 11:25 ]

ASSUME makes an ASS out of U and ME


Acties:
  • 0 Henk 'm!

  • whoami
  • Registratie: December 2000
  • Laatst online: 01:56
Wilde schreef op dinsdag 22 juli 2008 @ 11:19:
Ik ben tijdens mijn opleiding veel in Java geprogrammeerd. als je daar een = operator gebruikt wordt een nieuwe verwijzing gelegd naar het object. Bijvoorbeeld:

object o1
object o2

o2 = 01;

Nu zijn o1 en o2 gelijk (ze wijzen naar hetzelfde objct).

Ik ben sinds een paar maanden in C# begonnen en merk dat het hier anders werkt.
Nee hoor, dat werkt precies hetzelfde, als je dit doet bij reference types (zoals classes).

Stel:
C#:
1
2
MyClass c = new MyClass();
MyClass b = c;

b & c zullen hier naar dezelfde instantie wijzen van die class. Die instantie bevind zich op de heap.
Om een referentie naar een bestaand object in de aanroep van een methode mee te geven gebruik je het REF(of out, maar dat terzijde) keyword. Maar hoe zit het nu met het java voorbeeld in het begin van me'n post ?
out & ref hebben een volledig andere betekenis.

out betekent dat de parameter een waarde kan verkrijgen in de method, en deze dus ook moet 'onthouden'. De variable die je als parameter meestuurt, hoeft niet geinitialiseerd te zijn, bv:
C#:
1
2
3
4
5
int i;

Melp( out i );

Console.WriteLine (i);

waarbij:
code:
1
2
3
4
private  Melp( out int i )
{
   i = 5;
}

Dan zal je variable 'i' na de aanroep van die 'Melp' method de waarde 5 hebben.

Met een ref parameter, wordt je variable 'by reference' naar de method doorgegeven, waardoor je de waarde van die variable kunt wijzigen.
Bij een value type, zoals bv een integer, heb je bv deze situatie:
C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
void Method1( ref int i )
{
    i = 7;
}

void Method2( int i )
{
    i = 2;
}

...
int a = 1;

Method2(a);
Console.WriteLine(a);
Method1(a);
Console.WriteLine(a);

Dit stukje code zal als output:
1
7
geven.

Bij reference types, moet je dit eigenlijk anders zien.
Stel, je hebt deze method (waarbij MyClass een reference type is (een class)):
C#:
1
2
3
4
5
6
7
8
9
10
11
void MyMethod( MyClass c )
{
    c.SomeProperty = "a";
}

...

MyClass c = new MyClass();
c.SomeProperty = "b";
MyMethod(c);
Console.WriteLine (c.SomeProperty);

Hier zal de output
a
zijn, ook al geef je je variable niet 'by ref' door. Je property is toch gewijzigd, omdat je de referentie waar 'c' zich bevind op de heap doorgeeft. Je kan dus alle properties van 'c' wijzigen.
Wat je niet kan doen, is de reference naar c (die op de stack zit), wijzigen. (Althans, deze wijziging zal niet meer zichtbaar zijn buiten de method aanroep).

Als je echter je reference type by ref doorgeeft, dan kan je wel de reference op de stack gaan wijzigen:
C#:
1
2
3
4
void MyMethod( ref MyClass c )
{
   c = new MyClass();
}

Hier ga je dus een nieuwe instantie aan c kunnen geven, en aangezien deze 'by ref' is doorgegeven, zal dit ook zo zijn buiten de method.
C#:
1
2
3
4
MyClass c = new MyClass();
Console.WriteLine (c.GetHashCode());
MyMethod (ref c);
Console.WriteLine (c.GetHashCode());

https://fgheysels.github.io/


Acties:
  • 0 Henk 'm!

  • Woy
  • Registratie: April 2000
  • Niet online

Woy

Moderator Devschuur®
Idd zoals Whoami het aangeeft klopt het.

Je moet echter wel oppassen dat je in C# ook user defined value types hebt. Dat is iets wat volgens mij niet in Java bestaat. Deze types gedragen zich dus ook anders dan Refference types.

“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!

  • EfBe
  • Registratie: Januari 2000
  • Niet online
rwb schreef op dinsdag 22 juli 2008 @ 12:10:
Idd zoals Whoami het aangeeft klopt het.

Je moet echter wel oppassen dat je in C# ook user defined value types hebt. Dat is iets wat volgens mij niet in Java bestaat. Deze types gedragen zich dus ook anders dan Refference types.
Een value type is een value type, wie die definieert is niet relevant. Waar jij op doelt is me dan ook niet duidelijk.

Value types zijn over het algemeen immutable, ze representeren een value. 'ref' wordt afgeraden in de meeste gevallen, want het is zelden nodig een reference te veranderen in een method: het levert minder onderhoudbare code op.

Creator of: LLBLGen Pro | Camera mods for games
Photography portfolio: https://fransbouma.com


Acties:
  • 0 Henk 'm!

  • whoami
  • Registratie: December 2000
  • Laatst online: 01:56
EfBe schreef op dinsdag 22 juli 2008 @ 12:15:
[...]
'ref' wordt afgeraden in de meeste gevallen, want het is zelden nodig een reference te veranderen in een method: het levert minder onderhoudbare code op.
Idd. Ik kan me trouwens niet zo direct een situatie voor de geest halen waar ik 'ref' absoluut nodig had ...

https://fgheysels.github.io/


Acties:
  • 0 Henk 'm!

  • Woy
  • Registratie: April 2000
  • Niet online

Woy

Moderator Devschuur®
EfBe schreef op dinsdag 22 juli 2008 @ 12:15:
[...]

Een value type is een value type, wie die definieert is niet relevant. Waar jij op doelt is me dan ook niet duidelijk.
Dat is wel waar natuurlijk, maar het is wel handig om te realiseren dat er in .NET meer value types zijn. In java zijn alleen de Primitive data types value types.

“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!

  • whoami
  • Registratie: December 2000
  • Laatst online: 01:56
Je wil dus zeggen dat je in Java geen user defined value types kunt maken ?
Dat wil dus zeggen dat je in Java geen 'structs' hebt bv, of dat structs in Java reference types zijn ?

https://fgheysels.github.io/


Acties:
  • 0 Henk 'm!

  • farlane
  • Registratie: Maart 2000
  • Laatst online: 16-09 22:43
out & ref hebben een volledig andere betekenis
Leg me dan nog eens een keer uit wat die volledig andere betekenis is want volgens mij is het ongeveer hetzelfde.

Somniferous whisperings of scarlet fields. Sleep calling me and in my dreams i wander. My reality is abandoned (I traverse afar). Not a care if I never everwake.


Acties:
  • 0 Henk 'm!

  • Woy
  • Registratie: April 2000
  • Niet online

Woy

Moderator Devschuur®
whoami schreef op dinsdag 22 juli 2008 @ 13:11:
Je wil dus zeggen dat je in Java geen user defined value types kunt maken ?
Dat wil dus zeggen dat je in Java geen 'structs' hebt bv, of dat structs in Java reference types zijn ?
Zover ik weet wel, maar dat kan ondertussen natuurlijk wel veranderd zijn. "Vroeger" toen ik nog in Java programeerde had je geen structs ieder geval

“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!

  • whoami
  • Registratie: December 2000
  • Laatst online: 01:56
farlane schreef op dinsdag 22 juli 2008 @ 14:00:
[...]


Leg me dan nog eens een keer uit wat die volledig andere betekenis is want volgens mij is het ongeveer hetzelfde.
out definieert een output parameter.

ref geeft een variable door als by reference.

Een output parameter moet niet geinitialiseert zijn voor je functie aanroep:
code:
1
2
int i;
Melp( out i );
kan bv perfect. De method 'melp' moet dan een waarde aan i geven. Indien je dit niet doet, krijg je een compiler error:
The out parameter 'i' must be assigned to before control leaves the current method
'ref' geeft dus aan dat je je var doorgeeft als 'by reference', dus je kan je parameter gaan wijzigen. (In het geval van een value type kan je dus de waarde van je parameter wijzigen, en blijft deze wijziging ook geldig na de method aanroep. In het geval van een reference type, kan je de reference wijzigen (zoals in m'n eerdere post).
rwb schreef op dinsdag 22 juli 2008 @ 14:09:
[...]

Zover ik weet wel, maar dat kan ondertussen natuurlijk wel veranderd zijn. "Vroeger" toen ik nog in Java programeerde had je geen structs ieder geval
vreemd.

[ Voor 12% gewijzigd door whoami op 22-07-2008 14:14 ]

https://fgheysels.github.io/


Acties:
  • 0 Henk 'm!

  • Janoz
  • Registratie: Oktober 2000
  • Laatst online: 16-09 09:15

Janoz

Moderator Devschuur®

!litemod

whoami schreef op dinsdag 22 juli 2008 @ 13:11:
Je wil dus zeggen dat je in Java geen user defined value types kunt maken ?
Dat wil dus zeggen dat je in Java geen 'structs' hebt bv, of dat structs in Java reference types zijn ?
Klopt, in Java heb je geen structs, alleen classes.

Ken Thompson's famous line from V6 UNIX is equaly applicable to this post:
'You are not expected to understand this'


Acties:
  • 0 Henk 'm!

  • farlane
  • Registratie: Maart 2000
  • Laatst online: 16-09 22:43
whoami schreef op dinsdag 22 juli 2008 @ 14:14:
[...]

out definieert een output parameter.

ref geeft een variable door als by reference.

Een output parameter moet niet geinitialiseert zijn voor je functie aanroep:
code:
1
2
int i;
Melp( out i );
kan bv perfect. De method 'melp' moet dan een waarde aan i geven. Indien je dit niet doet, krijg je een compiler error:

[...]


'ref' geeft dus aan dat je je var doorgeeft als 'by reference', dus je kan je parameter gaan wijzigen. (In het geval van een value type kan je dus de waarde van je parameter wijzigen, en blijft deze wijziging ook geldig na de method aanroep. In het geval van een reference type, kan je de reference wijzigen (zoals in m'n eerdere post).
Het enige verschil dat ik hierin zie is dat bij een out parameter de parameter verplicht moet worden gewijzigd en bij een ref parameter niet. ( Ik kan me niet voorstellen dat er andere bytecode wordt gegenereerd eigenlijk, al heb ik dat niet gecontroleerd )

Het is me een raadsel waarom men dit verschil maakt eerlijk gezegd.

Somniferous whisperings of scarlet fields. Sleep calling me and in my dreams i wander. My reality is abandoned (I traverse afar). Not a care if I never everwake.


Acties:
  • 0 Henk 'm!

  • whoami
  • Registratie: December 2000
  • Laatst online: 01:56
Ik vind het goed dat men dit verschil maakt, al is het maar om explicieter en duidelijker te zijn.
out definieert een output parameter, ref een pass by reference parameter.

https://fgheysels.github.io/


Acties:
  • 0 Henk 'm!

  • EfBe
  • Registratie: Januari 2000
  • Niet online
het verschil tussen out en ref is overigens C# specifiek. De CLR kent alleen het fenomeen ref.

Creator of: LLBLGen Pro | Camera mods for games
Photography portfolio: https://fransbouma.com


Acties:
  • 0 Henk 'm!

  • farlane
  • Registratie: Maart 2000
  • Laatst online: 16-09 22:43
whoami schreef op woensdag 23 juli 2008 @ 14:32:
Ik vind het goed dat men dit verschil maakt, al is het maar om explicieter en duidelijker te zijn.
out definieert een output parameter, ref een pass by reference parameter.
Ik vind het ook duidelijker, maar zolang je met ref ook een output parameter kunt maken vind ik het onzinnig om het verschil te maken.
EfBe schreef op woensdag 23 juli 2008 @ 17:09:
het verschil tussen out en ref is overigens C# specifiek. De CLR kent alleen het fenomeen ref.
Dat bevestigt mijn vermoeden.
DrDelete schreef op donderdag 24 juli 2008 @ 07:47:
bij ref geef je een vooraf geinitialiseerde variabele mee, bij out juist niet.
Ik snap wat het "verschil" is tussen de twee, maar leg me eens uit wat het grote voordeel is van "out" dat het een geheel nieuw keyword rechtvaardigt.

Btw, als ik mijn variabelen bij declaratie initialiseer ( wat ik zoveel mogelijk doe ) is het verschil nog kleiner.

[ Voor 26% gewijzigd door farlane op 24-07-2008 10:54 ]

Somniferous whisperings of scarlet fields. Sleep calling me and in my dreams i wander. My reality is abandoned (I traverse afar). Not a care if I never everwake.


Acties:
  • 0 Henk 'm!

  • DrDelete
  • Registratie: Oktober 2000
  • Laatst online: 21:44
farlane schreef op dinsdag 22 juli 2008 @ 14:00:
[...]


Leg me dan nog eens een keer uit wat die volledig andere betekenis is want volgens mij is het ongeveer hetzelfde.
bij ref geef je een vooraf geinitialiseerde variabele mee, bij out juist niet.

Acties:
  • 0 Henk 'm!

  • roy-t
  • Registratie: Oktober 2004
  • Laatst online: 08-09 11:33
DrDelete schreef op donderdag 24 juli 2008 @ 07:47:
[...]


bij ref geef je een vooraf geinitialiseerde variabele mee, bij out juist niet.
Inderdaad out en ref zijn niet voor de compiler maar voor de programmeur om tijdens het debuggen/compilen al "Variable not initialized" errors te kunnen geven en programmeurs zo voor fouten te kunnen behouden.

Als ik het goed heb, moet je bij out ook persee een waarde asignen aan de variabele anders krijg je ook warnings (maar dat zou ik even moeten testen).

~ Mijn prog blog!


Acties:
  • 0 Henk 'm!

  • whoami
  • Registratie: December 2000
  • Laatst online: 01:56
roy-t schreef op donderdag 24 juli 2008 @ 11:13:
[...]

Als ik het goed heb, moet je bij out ook persee een waarde asignen aan de variabele anders krijg je ook warnings (maar dat zou ik even moeten testen).
In de method waar je variable een out parameter is, moet je idd een waarde aan die parameter assignen.
Je krijgt echter geen compiler-warning, maar een compiler-error. :)

Trouwens, hoe zit het nou precies met .... de topicstarter ? Die hebben we hier niet meer gezien ...

[ Voor 15% gewijzigd door whoami op 24-07-2008 11:31 ]

https://fgheysels.github.io/


Acties:
  • 0 Henk 'm!

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

.oisyn

Moderator Devschuur®

Demotivational Speaker

farlane schreef op woensdag 23 juli 2008 @ 17:24:
Ik snap wat het "verschil" is tussen de twee, maar leg me eens uit wat het grote voordeel is van "out" dat het een geheel nieuw keyword rechtvaardigt.
Semantiek. 'ref' is in/out. 'out' is natuurlijk alleen out. Ik vind het wel nuttig, net als bijvoorbeeld in deze C++ code:

C++:
1
2
3
4
5
6
7
#define IN
#define OUT
#define INOUT

// ...

void Foo(INOUT Bar * a, OUT Baz * b);

Het verschil natuurlijk zijnde dat de compiler in C# de semantiek zelf ook snapt, terwijl dat in C++ alleen iets voor de programmeur zelf is.

.edit: het gaat natuurlijk met name om het verschil tussen OUT en INOUT - voor refs die alleen IN zijn kun je beter gewoon const gebruiken. Wat je ermee aangeeft is of een functie het object ook als input gebruikt, of dat ie er alleen maar een nieuwe waarde aan toekent. Feitelijk exact hetzelfde als het verschil tussen 'ref' en 'out' in C#

[ Voor 27% gewijzigd door .oisyn op 24-07-2008 15:10 ]

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.

Pagina: 1