Parameter transmission in C #
I. Primitive Types
For basic types, the situation seems to be simple. Suppose we have the following programs:
// EXAMPLE 1
Using system;
Class mainclass {
Public static void main () {
CHAR C = 'a';
Console.writeline ("1 #: c =" c);
PRMTVFUN (C);
Console.writeline ("2 #: c =" c);
}
Static void prmatvfun (char c) {
C ;
}
}
Compile it and run with CSC, you can find that the output of the console is:
1 #: c = a
2 #: c = a
This indicates that the method prmatvfun (char c) does not truly modify the CHAR variable corresponding to the parameter C. What is the reason? In MSDN, we see this description:
If a parameter is declared for a method without ref or out, the parameter can have a value associated with it. That value can be changed in the method, but the changed value will not be retained when control passes back to the calling procedure.
If you want to achieve modification, it is quite simple, just use C # keyword REF or OUT. About the Ref keyword, you can refer to MSDN (I am using MSDN Library - January 2002):
Ms-help: //ms.msdnqtr.2002jan.msdnqtr.2002jan.1033/csref/html/vclrfref.htm.
And the OUT keyword, you can refer to:
MS-help: //ms.msdnqtr.2002jan.3033/csref/html/vclrfout.htm
As seen in the documentation, these two keywords do not differ much. Their main difference is: If the variable is incorporated into the REF mode, it must be initialized before the function; if the variable is as an OUT The way in which the function must be assigned to the function body.
Here is an example:
// EXAMPLE 2
Using system;
Class mainclass {
Public static void main () {
CHAR C = 'm'; // must initialize first
Console.writeline ("1 #: c =" c);
PRMTVFUNWITHREF (REF C); // must explicitly use the REF keyword
Console.writeline ("2 #: c =" c);
CHAR D; // does not have to initialize, of course, can also be initialized
//Console.writeline ("3#: D = " D);
PRMTVFUNWITHOUT (OUT D); // Must explicitly use OUT keywords
Console.writeline ("4 #: D =" D);
}
Static void prmatvfun (char c) {
C = 's'; // The change value will not be retained when control passes Back to the calling process
}
Static void prmatvfunwithref (Ref char c) {// uses the REF keyword, c must be initialized
C = 's';
}
Static void prmatvfunwithout (out char c) {// uses OUT keyword c = 'n'; // must assign CV operations in the function body
}
}
This is its output:
1 #: c = m
2 #: c = s
4 #: d = n
There is no doubt that this modification is successful.
in conclusion:
For the basic type (Primitive Types), when the parameter as a function is passed, if the REF or OUT keyword is not used, any modifications to which it will not be used in the function body. If it is used correctly REF or OUT keyword, then the operation of the parameter, its corresponding "this respect" also feels the same.
II. Object Types
For object types, if you think the relative complexity of its structure, it will face a case where the basic type is more complicated, that's wrong. In fact, it is not complex:
// EXAMPLE 3
Using system;
Class testclass {// a class for test
PRIVATE CHAR C;
Public char C {// Simple properties
SET {
C = Value;
}
Get {
Return C;
}
}
//Constructor
Public TestClass (char C) {
THIS.C = C;
}
}
/ / ============ TestClass defines this end ===========
Class mainclass {// main class
Public static void main () {
TestClass TC = New TestClass ('A');
Console.writeline ("1 #:" tc.c);
Objfun (TC, 'B');
Console.writeline ("2 #:" Tc.c);
Objfunwithref (REF TC, 'C');
Console.writeline ("3 #:" tc.c);
Objfunwithout (Out TC, 'D'); // Simple use of TC here, which is the same as the object effect of NEW.
Console.writeline ("4 #:" Tc.c);
}
Static void objfun (TestClass TC, Char newc) {
Tc.c = newc;
}
Static void objfunwithref (Ref testclass tc, char newc) {
Tc.c = newc;
}
Static void objfunwithout (Out Testclass TC, CHAR C) {
Tc = New TestClass (C);
}
}
In the above program, a TestClass class is first defined. This class is quite simple, only one constructor and the CHAR type C property are provided. In the mainclass class, we define some test functions similar to the basic type. Judging the transmission mode of the object type. The output of the entire program is:
1 #: a
2 #: b
3 #: c
4 #: D
As can be seen from these outputs, when the object type object is passed as a function of the function (whether or not to use the keyword REF / OUT et al.), Any modifications made in the function body will be modified to the object. Is this this? Answer It is frustrating NO! We tried to rewrite objfun and objfunwithref as the following form:
// eXample 4
Static void objfun (TestClass TC, Char newc) {
Tc = New TestClass ('a'); // Plus this statementtc.c = newc; / * In our example, its value is 'b' * /
}
Static void objfunwithref (Ref testclass tc, char newc) {
Tc = New TestClass ('a'); // Plus this statement
Tc.c = newc; / * In our example, its value is 'c' * /
}
Then compile, run the program, this time the output of the program becomes:
1 #: a
2 #: a
3 #: c
4 #: D
Not surprising, you may be surprised to 2 # and 3 # output. If the previous question answer is YES, the output of 2 # is undoubtedly wrong. So, how is the parameter of the object type object function to pass? • This problem can be divided into two parts:
1> Do not use REF / OUT keywords
For this situation, the passage of the parameters and the basic type are consistent: Pass by value. In order to accept this point of view, you have to know the concept of reference (this is the same as the reference in Java. When we Write down:
TestClass TC = New TestClass ('A');
You may not know that you are already using reference. On the other hand, you may think you have created a TestClass class object --- tc. However, I regretfully tell you, you have created one TestClass class object, but it is not TC, but a reference to the Heap on the Heap in New TestClass ('A') .TC is a reference to this object, or pointing to the pointer to that object. such:
When the parameter is passed, as I said: Pass by value. Why is the value here? It is a reference! When calling objfun (testclass, char), such as the basic type, generate a reference copy (COPY) Naturally, this reference copy also points to the same object pointing to the argument:
From here we can see, if we modify a property in the function body (like Example 3), because the object points to the Copy Of TC and TC is the same, the modification naturally reflects the object as a field. Body. This is consistent with the situation we see in the output of Example 3.
If the new keyword is used like Example 4, according to our current understanding, it should be like this:
From this figure, we can see that TC is still pointing to the original object (represented by plus order in the figure), and due to the role of New, the Copy Of TC is pointing to the HEAP. A new object (represented by plus double underscore in the figure). In this way, the operation of the copy of the TC in the function body does not affect the original object. For our EXAMPLE 4, it is called Objfun. After still output 2 #: a.
2> Using Ref / Out Keywords
For object type instances that use REF / OUT keyword modified, a referenced copy is not generated, but directly use the original reference (naturally pointing to the original object). In this way, any operation will be reflected in the ground to the original Object. If we rewrite the Objfunwithref (Ref TestClass, Char) as:
Static void objfunwithref (Ref testclass tc, char newc) {
Tc = New TestClass ('x');
//tc.c = newc;
}
Due to the role of REF, the original object will become garbage, which will ultimately be recycled by GC. At the same time, TC is associated with another object created on HEAP. Therefore, the following output is generated:
3 #: x
in conclusion:
For object type (Object Types), when it is passed as a function of the function, if the REF or OUT keyword is not used, the passed is a reference, and generates a referenced copy. If the REF or OUT keyword is used correctly, Then use the original reference directly, and the corresponding "this respect" is also subject to the operation of the reference.
Structure type (STRUCT)
As we all know, the type of Struct (Structure) is still retained in C #. For example, the system.drawing.rectangle class, system.drawing.point class is all struct type. So how is the object of the structural type, how is the parameter passed? Let's look at the following procedure: struct teststruct {// Note this is a structure
PRIVATE CHAR C;
Public char c {
SET {
C = Value;
}
Get {
Return C;
}
}
Public Teststruct (char C) {
THIS.C = C;
}
}
Similarly, let's test the way the parameters are passed:
Class mainclass {// main class
Public static void main () {
Teststruct TS = New Teststruct ('a');
Console.writeline ("1 #:" Ts.c);
StructFun (TS, 'B');
Console.writeline ("2 #:" Ts.c);
StructFunwithref (Ref TS, 'C');
Console.writeline ("3 #:" Ts.c);
StructFunwithout (OUT TS, 'D');
Console.writeline ("4 #:" Ts.c);
}
Static void structfun (Teststruct TS, Char newc) {
Ts.c = newc;
}
Static void structfunwithref (Ref teststruct ts, char newc) {
Ts.c = newc;
}
Static void structfunwithout (Out Teststruct TS, CHAR C) {
TS = New Teststruct (C);
}
}
Compile and run the program, you can see this output:
1 #: a
2 #: a
3 #: c
4 #: D
This indicates that StructFun (Teststruct, char) is unsuccessful. Thus, it can be explained that the parameter delivery of Structs is consistent with basic types (from here, this conclusion seems to be a bit arbitrary, but we can pass more testing To reveal this).
Fourth. Conclusion
We know that data types in C # are divided into two categories: value types and reference types. Basic types and struct types belong to the former, the object type belongs to the latter. According to the previous discussion, we It can be drawn as follows:
1). Value type
1A). Do not use Ref / Out keywords
When the parameter passes, the value of the value is generated. The operation of the copy does not affect the original value.
1B). Use the REF / OUT keyword
Use the original variables directly to the original variables in the original variables.
2). Quote type
2A). Do not use the Ref / Out keyword
When the parameter passes, a reference copy is generated. If the copy is still pointing to the original object, the modification will affect the original object, otherwise it will not.
2b). Use the REF / OUT keyword
With the original reference, all modifications will be reflected in the original object.