A deep understanding of C #'s value passing and reference passing calls,

Source: Internet
Author: User

A deep understanding of C #'s value passing and reference passing calls,

Value Transfer and Reference call are related to almost all mainstream languages. Next I will talk about my understanding of value transfer and reference transfer calls in C.

1. General understanding of value transfer and reference transfer in C #
  • If the passed parameter is a primitive type (int, float, etc.) or struct (struct), it is called to pass the value.
  • If the passed parameter is a class, it is a reference call.
  • If the input parameter contains the ref or out keyword, it is called by reference.

The verification sample code is as follows:

 

 

 

View sourceprint?

01 using System;

02

03 public class ArgsByRefOrValue

04 {

05 public static void Main (string [] args)

06 {

07 // Experiment 1. Call for passing values-primitive type

08 int I = 10;

09 Console. WriteLine ("before call ChangeByInt: I =" + I. ToString ());

10 ChangeByInt (I );

11 Console. WriteLine ("after call ChangeByInt: I =" + I. ToString ());

12

13 Console. writeLine ("========================================== ========= ");

14 // Experiment 2. Call value transfer-struct

15 Person_val p_val = new Person_val ();

16 p_val.name = "old val name ";

17 Console. WriteLine ("before call ChangeByStruct: p_val.name =" + p_val.name );

18 ChangeByStruct (p_val );

19 Console. WriteLine ("after call ChangeByStruct: p_val.name =" + p_val.name );

20

21 Console. writeLine ("========================================== ========= ");

22 // experiment 3. Upload Reference call-class

23 Person_ref p_ref = new Person_ref ();

24 p_ref.name = "old ref name ";

25 Console. WriteLine ("before call ChangeByClass: p_ref.name =" + p_ref.name );

26 ChangeByClass (p_ref );

27 Console. WriteLine ("after call ChangeByClass: p_ref.name =" + p_ref.name );

28

29 Console. writeLine ("========================================== ========= ");

30 // Experiment 4. Upload Reference call -- use ref

31 Person_ref p = new Person_ref ();

32 p. name = "old ref name ";

33 Console. WriteLine ("before call ChangeByClassRef: p. name =" + p. name );

34 ChangeByClassRef (ref p );

35 Console. WriteLine ("after call ChangeByClassRef: p. name =" + p. name );

36

37 Console. ReadKey (true );

38}

39

40 static void ChangeByInt (int I)

41 {

42 I = I + 10;

43 Console. WriteLine ("when calling ChangeByInt: I =" + I. ToString ());

44}

45

46 static void ChangeByStruct (Person_val p_val)

47 {

48 p_val.name = "new val name ";

49 Console. WriteLine ("when calling ChangeByStruct: p_val.name =" + p_val.name );

50}

51

52 static void ChangeByClass (Person_ref p_ref)

53 {

54 p_ref.name = "new ref name ";

55 Console. WriteLine ("when calling ChangeByClass: p_ref.name =" + p_ref.name );

56}

57

58 static void ChangeByClassRef (ref Person_ref p)

59 {

60 p. name = "new ref name ";

61 Console. WriteLine ("when calling ChangeByClassRef: p. name =" + p. name );

62}

63}

64

65 public struct Person_val

66 {

67 public string name;

68}

69

70 public class Person_ref

71 {

72 public string name;

73}

 

The running result is as follows:

 

 

It seems that the above Code isLab 3AndLab 4Is the same, that is, for a class, no matter the ref or out is added, it is a reference call.

In fact, this is only a superficial phenomenon. If you change the code a bit, the results will be different.

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 for passing values -- 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. Call value transfer-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. Upload Reference call-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. Upload Reference call -- use 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. Upload Reference call -- the Class re-creates an object in the called Function

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. Upload Reference call -- use ref to re-create an object in the called Function

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}

086

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

100 public class Person_ref

101 {

102 public string name;

103}

 

The running result is:

 

Lab 5Even if the parameter is a class, if no ref is added, it is also called.

The following introduces my understanding.

2. If there is no ref, even if the parameter is of the reference type (class), it can be regarded as a value passing call.

When the parameter is of the reference type, a copy of the address of the reference type is passed. "A copy of the address of the reference type" is the "value" of the value transfer call ".

Note that what is passed here is the address of this reference typeOne copyInstead of the address of the reference type.

The following figure illustrates the memory usage in experiment 3, Experiment 5, and Experiment 6.

2.1 First, experiment 3

The memory figure in experiment 3 is as follows. The real parameter is the Person_ref object outside the ChangeByClass function, and the form parameter is the Person_ref object in the ChangeByClass function.

We can see that after the new arguments are passed out, the memory is allocated on the managed stack, and the object pointer is saved on the stack.

After the ChangeByClass function is called,Real parameter p_valCopy a copyParametersNote:P_val (real parameter)AndP_val (parameter)Is to point to the same address on the managed stack.

SoWhen no ref is available, even if the parameter is of the reference type (class), it can be regarded as a value passing call.The value here is the address of the object in the managed heap (0x1000 ).

After the ChangeByClass function is calledP_val (parameter)Modified the value of the name attribute becauseP_val (real parameter)AndP_val (parameter)Is pointing to the same address on the hosting stack, soP_val (real parameter)The name attribute is also modified.

2.2 and then Experiment 5

From the execution results of experiment 3 above, it seems that the reference call is passed, because the change of the form parameter leads to the change of the real parameter.

The following Experiment 5 shows that,P_val (parameter)AndP_val (real parameter)Not the same variable,P_val (real parameter).

We can see that the first step is the same as experiment 3, but it is different after the ChangeByClassNew function is called.

In the ChangeByClassNew functionP_val (parameter)The memory is re-allocated (new Operation) so that it points to the new address (0x1100), for example:

SoP_val (parameter)When the name attribute of is changed,P_val (real parameter)The name attribute of is still unchanged.

2.3 Experiment 6

I think Experiment 6 is a real reference transfer call. This is the first image.

After the ref keyword is added to the parameter, the address of the object in the managed heap (0x1000) is not actually passed, but on the stack.P_val (real parameter)(0x0001 ).

So here the real parameters and the form parameters are the same thing on the stack, there is no difference. I think this is the real transfer Reference call.

Then the ChangeByClassRefNew function is called.P_val (parameter)The memory is re-allocated (new Operation) so that it points to the new address (0x1100 ).

BecauseP_val (parameter)YesP_val (real parameter), SoP_val (parameter)After the name attribute of is changedP_val (real parameter)The name attribute is also changed.

The previously 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), it is called to pass the value.

 

 

 

 

 

 

 

 

 

  • If the input parameter contains the ref or out keyword, it is called by reference.
  • If the passed parameter is a class and there is no ref or out Keyword:

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.