The call to call and the invocation of a reference are questions that almost all major languages can relate to, and I'll talk about my understanding of the invocation of values in C # and the invocation of a reference.
1. General understanding of invocation of values in C # and invocation of reference
- If the passed parameter is a primitive type (int,float, etc.) or struct (struct), then it is a value call.
- If the passed argument is a class, then it is a reference call.
- If there is a ref or out keyword before the passed argument, it is a reference call.
The code for the validation example is as follows:
View Sourceprint?
Using System;
02
public class Argsbyreforvalue
04 {
public static void Main (string[] args)
06 {
07//Experiment 1. Call to Value--primitive type
an int i = 10;
Console.WriteLine ("Before Call changebyint:i =" + i.tostring ());
Ten changebyint (i);
Console.WriteLine ("After call changebyint:i =" + i.tostring ());
12
Console.WriteLine ("==============================================");
14//Experiment 2. Value call-struct
Person_val p_val = new Person_val ();
P_val.name = "Old Val name";
Console.WriteLine ("Before Call ChangeByStruct:p_val.name =" + P_val.name);
Changebystruct (P_val);
Console.WriteLine ("After call ChangeByStruct:p_val.name =" + P_val.name);
20
Console.WriteLine ("==============================================");
22//Experiment 3. Reference invocation-Class
Person_ref p_ref = new Person_ref ();
P_ref.name = "Old ref name";
Console.WriteLine ("Before Call ChangeByClass:p_ref.name =" + P_ref.name);
Changebyclass (P_REF);
Console.WriteLine ("After call ChangeByClass:p_ref.name =" + P_ref.name);
28
Console.WriteLine ("==============================================");
30//Experiment 4. Reference invocation--using ref
Person_ref p = new Person_ref ();
P.name = "Old ref name";
Console.WriteLine ("Before Call Changebyclassref:p.name =" + p.name);
Changebyclassref (ref p);
Console.WriteLine ("After call Changebyclassref:p.name =" + p.name);
36
Panax Notoginseng Console.readkey (true);
38}
39
+ static void Changebyint (int i)
41 {
i = i + 10;
Console.WriteLine ("When calling changebyint:i =" + i.tostring ());
44}
45
changebystruct static void (Person_val P_val)
47 {
P_val.name = "New Val name";
Console.WriteLine ("When calling ChangeByStruct:p_val.name =" + P_val.name);
50}
51
Changebyclass static void (Person_ref P_ref)
53 {
P_ref.name = "New ref name";
Console.WriteLine ("When calling ChangeByClass:p_ref.name =" + P_ref.name);
56}
57
Changebyclassref static void (ref PERSON_REF p)
59 {
P.name = "New ref name";
Console.WriteLine ("When calling Changebyclassref:p.name =" + p.name);
62}
63}
64
Person_val public struct
66 {
* * public string name;
68}
69
-Public class Person_ref
71 {
The public string name;
73}
The results of the operation are as follows:
It seems that experiment 3 and Experiment 4 are the same in the code above, that is, for class, whether it is a ref or out, it is a reference call.
In fact, this is only a superficial phenomenon, as long as the code changes slightly, the result is not the same.
Modify the code above and add two more experiments.
001 using System;
002
003 public class Argsbyreforvalue
004 {
005 public static void Main (string[] args)
006 {
007//Experiment 1. Call to Value--primitive type
008 int i = 10;
009 Console.WriteLine ("Before Call changebyint:i =" + i.tostring ());
010 Changebyint (i);
011 Console.WriteLine ("After call changebyint:i =" + i.tostring ());
012
013 Console.WriteLine ("==============================================");
014//Experiment 2. Value call-struct
015 Person_val p_val = new Person_val ();
016 P_val.name = "Old Val name";
017 Console.WriteLine ("Before Call ChangeByStruct:p_val.name =" + P_val.name);
018 changebystruct (P_val);
019 Console.WriteLine ("After call ChangeByStruct:p_val.name =" + P_val.name);
020
021 Console.WriteLine ("==============================================");
022//Experiment 3. Reference invocation-Class
023 Person_ref p_ref = new Person_ref ();
024 P_ref.name = "Old ref name";
025 Console.WriteLine ("Before Call ChangeByClass:p_ref.name =" + P_ref.name);
026 Changebyclass (P_REF);
027 Console.WriteLine ("After call ChangeByClass:p_ref.name =" + P_ref.name);
028
029 Console.WriteLine ("==============================================");
030//Experiment 4. Reference invocation--using ref
031 Person_ref p = new Person_ref ();
032 p.name = "Old ref name";
033 Console.WriteLine ("Before Call Changebyclassref:p.name =" + p.name);
034 changebyclassref (ref P);
035 Console.WriteLine ("After call Changebyclassref:p.name =" + p.name);
036
037 Console.WriteLine ("==============================================");
038//Experiment 5. Invocation of a reference--class in the function called to re-new an object
039 person_ref p_ref_new = new Person_ref ();
040 P_ref_new.name = "Old new ref name";
041 Console.WriteLine ("Before Call ChangeByClassNew:p_ref_new.name =" + P_ref_new.name);
042 changebyclassnew (p_ref_new);
043 Console.WriteLine ("After call ChangeByClassNew:p_ref_new.name =" + P_ref_new.name);
044
045 Console.WriteLine ("==============================================");
046//Experiment 6. Reference invocation--re-new an object using ref in the function called
047 person_ref p_new = new Person_ref ();
048 p_new.name = "Old new ref name";
049 Console.WriteLine ("Before Call ChangeByClassRefNew:p_new.name =" + P_new.name);
050 Changebyclassrefnew (ref p_new);
051 Console.WriteLine ("After call ChangeByClassRefNew:p_new.name =" + P_new.name);
052
053 Console.readkey (TRUE);
054}
055
056 static void Changebyint (int i)
057 {
058 i = i + 10;
059 Console.WriteLine ("When calling changebyint:i =" + i.tostring ());
060}
061
062 static void Changebystruct (Person_val p_val)
063 {
064 p_val.name = "new Val name";
065 Console.WriteLine ("When calling ChangeByStruct:p_val.name =" + P_val.name);
066}
067
068 static void Changebyclass (Person_ref p_ref)
069 {
070 P_ref.name = "New ref name";
071 Console.WriteLine ("When calling ChangeByClass:p_ref.name =" + P_ref.name);
072}
073
074 static void Changebyclassref (ref person_ref P)
075 {
076 p.name = "New ref name";
077 Console.WriteLine ("When calling Changebyclassref:p.name =" + p.name);
078}
079
080 static void Changebyclassnew (Person_ref p_ref_new)
081 {
082 p_ref_new = new Person_ref ();
083 P_ref_new.name = "New ref name";
084 Console.WriteLine ("When calling ChangeByClassNew:p_ref_new.name =" + P_ref_new.name);
085}
18W
087 static void Changebyclassrefnew (ref person_ref p_new)
088 {
089 p_new = new Person_ref ();
090 P_new.name = "New ref name";
091 Console.WriteLine ("When calling ChangeByClassRefNew:p_new.name =" + P_new.name);
092}
093}
094
095 public struct Person_val
096 {
097 public string name;
098}
099
public class Person_ref
101 {
102 public string name;
103}
The result of the operation is:
The running result of Experiment 5 seems to indicate that even if the parameter is class, it is called as long as it is not ref.
The following leads to my understanding.
2. When there is no ref, even if the argument is a reference type (class), it can be considered a value call
When the argument is a reference type, a copy of the address of the reference type is passed, and a copy of the address of the reference type is the value of the value call.
Note that this is a copy of the address of the reference type, not the address of the reference type.
The following will be illustrated in the form of the above experiment 3, Experiment 5 and experiment 6 in the memory situation.
2.1 First Experiment 3
The memory diagram of Experiment 3 is as follows: The argument is a Person_ref object outside the function Changebyclass, and the formal parameter is the Person_ref object within the function Changebyclass.
We can see that when the argument new comes out, it allocates memory on the managed heap and holds a pointer to the object on the stack.
After calling the function Changebyclass, since there is no ref parameter, the argument p_val on the stack is copied as a formal parameter , note that p_val (argument ) and p_val (formal parameter) is to point to the same address on the managed heap.
So without ref, even if the argument is a reference type (class), it can be called a value call , where the value is the address of the object in the managed heap (0x1000).
After calling the function Changebyclass, the value of the Name property is modified by p_val (formal parameter ), because p_val (argument ) and p_val (formal parameter) point to the same address on the managed heap, so the outside of the function The Name property of the p_val (argument) has also been modified.
2.2, then experiment 5.
The above experiment 3 seems to be a reference call from the execution result, because the change of the formal parameter leads to the change of the argument.
As you can see in experiment 5 below,p_val (formal parameters) and p_val (arguments) are not the same variable, but a copy of the p_val (argument ).
You can see that the first step is the same as experiment 3, but after calling the function changebyclassnew, it is not the same.
In function Changebyclassnew, the memory (new operation) is reassigned to the p_val (parameter) so that it points to the new address (0x1100), such as:
So when the name property of the p_val (formal parameter) is changed, the Name property of thep_val (argument) remains unchanged.
2.3 And finally the experiment 6.
I think experiment 6 is really a reference call. No nonsense, directly on the first figure.
After the REF keyword is added to the parameter, it is not the address (0x1000) of the object in the managed heap, but the address of the p_val ( 0x0001) on the stack.
So here the arguments and the parameters are the same thing on the stack, and there is no difference. I think this is the real invocation of the reference.
The function changebyclassrefnew is then called, and the p_val (parameter) is reassigned to the new address (0x1100) in the function.
Since the p_val (formal parameter) is p_val (argument), the Name property of the p_val (formal parameter) is changed after the p_val (argument) outside the function changebyclassrefnew The name attribute has also been changed.
The originally allocated object (address 0x1000) has not been referenced, and will be recycled by GC at any time.
3. Conclusion
- If the passed parameter is a primitive type (int,float, etc.) or struct (struct), then it is a value call.
- If there is a ref or out keyword before the passed argument, it is a reference call.
- If the passed argument is a class and there is no ref or out keyword:
- If the parameter is re-assigned in the called function (new operation), then the execution result is similar to the value call
- If the parameter is not re-allocated in the calling function, the passed parameter is used directly, then the execution result is similar to the reference call
Deep understanding of C # 's call to call and reference invocation