正确理解C#中的ref关键字
最近有人问到 ref 关键字的正确用法,下面我们来举例说明。其实要更好的理解 ref 关键字,结合 C++ 代码更加容易一些。另外在开始我们的例子之前,需要提前说明几点:C# 中的数据有两种类型:引用类型(reference types)和值类型(value types)。 简单类型(包括int, long, double等)和结构(structs)都是值类型,而其他的类都是引用类型。 简单类型在传值的时候会做复制操作,而引用类型只是传递引用,就像 C++ 中的指针一样。 注意 structs 在 C# 和 C++ 中的区别。在 C++ 中, structs 和类基本相同(except that the default inheritance and default access are public rather than private)。 而在 C# 中,structs 和类有很大的区别。其中最大的区别(我个人觉得,同时也是容易忽略的一个地方)可能就是它是值类型,而不是引用类型。
下面这段代码是 MSDN 中的例子:
[color=#008000]//[/color][color=#008000] cs_ref.cs [/color]
[color=#0000ff]using[/color][color=#000000] System;[/color][color=#0000ff]public[/color]
[color=#0000ff]class[/color][color=#000000] MyClass{[/color][color=#0000ff]public[/color]
[color=#0000ff]static[/color]
[color=#0000ff]void[/color][color=#000000] TestRef([/color][color=#0000ff]ref[/color]
[color=#0000ff]char[/color][color=#000000] i){[/color][color=#008000]//[/color][color=#008000] The value of i will be changed in the calling method [/color]
[color=#000000]i [/color][color=#000000]=[/color]
[color=#000000]'[/color][color=#000000]b[/color][color=#000000]'[/color][color=#000000];}[/color][color=#0000ff]public[/color]
[color=#0000ff]static[/color]
[color=#0000ff]void[/color][color=#000000] TestNoRef([/color][color=#0000ff]char[/color][color=#000000] i){[/color][color=#008000]//[/color][color=#008000] The value of i will be unchanged in the calling method [/color]
[color=#000000]i [/color][color=#000000]=[/color]
[color=#000000]'[/color][color=#000000]c[/color][color=#000000]'[/color][color=#000000];}[/color][color=#008000]//[/color][color=#008000] This method passes a variable as a ref parameter; the value of the[/color][color=#008000]//[/color][color=#008000] variable is changed after control passes back to this method.[/color][color=#008000]//[/color][color=#008000] The same variable is passed as a value parameter; the value of the[/color][color=#008000]//[/color][color=#008000] variable is unchanged after control is passed back to this method. [/color]
[color=#0000ff]public[/color]
[color=#0000ff]static[/color]
[color=#0000ff]void[/color][color=#000000] Main(){[/color][color=#0000ff]char[/color][color=#000000] i [/color][color=#000000]=[/color]
[color=#000000]'[/color][color=#000000]a[/color][color=#000000]'[/color][color=#000000]; [/color][color=#008000]//[/color][color=#008000] variable must be initialized [/color]
[color=#000000]TestRef([/color][color=#0000ff]ref[/color][color=#000000] i); [/color][color=#008000]//[/color][color=#008000] the arg must be passed as ref [/color]
[color=#000000]Console.WriteLine(i);TestNoRef(i);Console.WriteLine(i);}} [/color]
大家很容易看出输出结果是:
b
b
那么如果把这个例子做一些新的改动,将值类型(这里用的是 char)改成引用类型,程序运行又是什么效果呢?
[color=#008000]//[/color][color=#008000] ----------------------------------------[/color][color=#008000]//[/color][color=#008000] MyClass definition [/color]
[color=#0000ff]public[/color]
[color=#0000ff]class[/color][color=#000000] MyClass{[/color][color=#0000ff]public[/color]
[color=#0000ff]int[/color][color=#000000] Value;}[/color][color=#008000]//[/color][color=#008000] ----------------------------------------[/color][color=#008000]//[/color][color=#008000] Tester methods [/color]
[color=#0000ff]public[/color]
[color=#0000ff]static[/color]
[color=#0000ff]void[/color][color=#000000] TestRef([/color][color=#0000ff]ref[/color][color=#000000] MyClass m){m.Value [/color][color=#000000]=[/color]
[color=#000000]10[/color][color=#000000];}[/color][color=#0000ff]public[/color]
[color=#0000ff]static[/color]
[color=#0000ff]void[/color][color=#000000] TestNoRef(MyClass m){m.Value [/color][color=#000000]=[/color]
[color=#000000]20[/color][color=#000000];}[/color][color=#0000ff]public[/color]
[color=#0000ff]static[/color]
[color=#0000ff]void[/color][color=#000000] TestCreateRef([/color][color=#0000ff]ref[/color][color=#000000] MyClass m){m [/color][color=#000000]=[/color]
[color=#0000ff]new[/color][color=#000000] MyClass();m.Value [/color][color=#000000]=[/color]
[color=#000000]100[/color][color=#000000];}[/color][color=#0000ff]public[/color]
[color=#0000ff]static[/color]
[color=#0000ff]void[/color][color=#000000] TestCreateNoRef(MyClass m){m [/color][color=#000000]=[/color]
[color=#0000ff]new[/color][color=#000000] MyClass();m.Value [/color][color=#000000]=[/color]
[color=#000000]200[/color][color=#000000];}[/color][color=#0000ff]public[/color]
[color=#0000ff]static[/color]
[color=#0000ff]void[/color][color=#000000] Main(){MyClass m [/color][color=#000000]=[/color]
[color=#0000ff]new[/color][color=#000000] MyClass();m.Value [/color][color=#000000]=[/color]
[color=#000000]1[/color][color=#000000];TestRef([/color][color=#0000ff]ref[/color][color=#000000] m);Console.WriteLine(m.Value);TestNoRef(m);Console.WriteLine(m.Value);TestCreateRef([/color][color=#0000ff]ref[/color][color=#000000] m);Console.WriteLine(m.Value);TestCreateNoRef(m);Console.WriteLine(m.Value);} [/color]
大家能马上给出正确的答案么?如果能,那看来你对 ref 的用法了解得还是非常不错的。其实如果大家对 C++ 比较熟悉的话,把这段代码换成 C++ 的就好理解的多了。
[color=#008000]//[/color][color=#008000] ----------------------------------------[/color][color=#008000]//[/color][color=#008000] MyClass definition [/color]
[color=#000000]#pragma once[/color][color=#0000ff]class[/color][color=#000000] MyClass{[/color][color=#0000ff]public[/color][color=#000000]:[/color][color=#0000ff]int[/color][color=#000000] Value;};typedef MyClass[/color][color=#000000]*[/color][color=#000000] MyClassPtr;[/color][color=#008000]//[/color][color=#008000] ----------------------------------------[/color][color=#008000]//[/color][color=#008000] Tester methods [/color]
[color=#0000ff]void[/color][color=#000000] TestRef([/color][color=#0000ff]char[/color][color=#000000]*[/color][color=#000000] i){[/color][color=#000000]*[/color][color=#000000]i [/color][color=#000000]=[/color]
[color=#000000]'[/color][color=#000000]b[/color][color=#000000]'[/color][color=#000000];}[/color][color=#0000ff]void[/color][color=#000000] TestNoRef([/color][color=#0000ff]char[/color][color=#000000] i){i [/color][color=#000000]=[/color]
[color=#000000]'[/color][color=#000000]c[/color][color=#000000]'[/color][color=#000000];}[/color][color=#0000ff]void[/color][color=#000000] TestRef(MyClassPtr[/color][color=#000000]*[/color][color=#000000] m){([/color][color=#000000]*[/color][color=#000000]m)[/color][color=#000000]->[/color][color=#000000]Value [/color][color=#000000]=[/color]
[color=#000000]10[/color][color=#000000];}[/color][color=#0000ff]void[/color][color=#000000] TestNoRef(MyClassPtr m){m[/color][color=#000000]->[/color][color=#000000]Value [/color][color=#000000]=[/color]
[color=#000000]20[/color][color=#000000];}[/color][color=#0000ff]void[/color][color=#000000] TestCreateRef(MyClassPtr[/color][color=#000000]*[/color][color=#000000] m){delete ([/color][color=#000000]*[/color][color=#000000]m);[/color][color=#000000]*[/color][color=#000000]m [/color][color=#000000]=[/color]
[color=#0000ff]new[/color][color=#000000] MyClass();([/color][color=#000000]*[/color][color=#000000]m)[/color][color=#000000]->[/color][color=#000000]Value [/color][color=#000000]=[/color]
[color=#000000]100[/color][color=#000000];}[/color][color=#0000ff]void[/color][color=#000000] TestCreateNoRef(MyClassPtr m){m [/color][color=#000000]=[/color]
[color=#0000ff]new[/color][color=#000000] MyClass();m[/color][color=#000000]->[/color][color=#000000]Value [/color][color=#000000]=[/color]
[color=#000000]200[/color][color=#000000];}[/color][color=#0000ff]int[/color][color=#000000] main([/color][color=#0000ff]int[/color][color=#000000] argc, [/color][color=#0000ff]char[/color][color=#000000]*[/color][color=#000000] argv[]){[/color][color=#0000ff]char[/color][color=#000000] c [/color][color=#000000]=[/color]
[color=#000000]'[/color][color=#000000]a[/color][color=#000000]'[/color][color=#000000];TestRef([/color][color=#000000]&[/color][color=#000000]c);printf([/color][color=#000000]"[/color][color=#000000]%c\n[/color][color=#000000]"[/color][color=#000000], c); [/color][color=#008000]//[/color][color=#008000] output: b [/color]
[color=#000000]TestNoRef(c);printf([/color][color=#000000]"[/color][color=#000000]%c\n[/color][color=#000000]"[/color][color=#000000], c); [/color][color=#008000]//[/color][color=#008000] output: b [/color]
[color=#000000]MyClassPtr m [/color][color=#000000]=[/color]
[color=#0000ff]new[/color][color=#000000] MyClass;m[/color][color=#000000]->[/color][color=#000000]Value [/color][color=#000000]=[/color]
[color=#000000]1[/color][color=#000000];TestRef([/color][color=#000000]&[/color][color=#000000]m);printf([/color][color=#000000]"[/color][color=#000000]%d\n[/color][color=#000000]"[/color][color=#000000], m[/color][color=#000000]->[/color][color=#000000]Value);TestNoRef(m);printf([/color][color=#000000]"[/color][color=#000000]%d\n[/color][color=#000000]"[/color][color=#000000], m[/color][color=#000000]->[/color][color=#000000]Value);TestCreateRef([/color][color=#000000]&[/color][color=#000000]m);printf([/color][color=#000000]"[/color][color=#000000]%d\n[/color][color=#000000]"[/color][color=#000000], m[/color][color=#000000]->[/color][color=#000000]Value);TestCreateNoRef(m);printf([/color][color=#000000]"[/color][color=#000000]%d\n[/color][color=#000000]"[/color][color=#000000], m[/color][color=#000000]->[/color][color=#000000]Value);delete m;[/color][color=#0000ff]return[/color]
[color=#000000]0[/color][color=#000000];} [/color]
这两段分别用 C# 和 C++ 实现的代码的输出结果都是一样的。后面用 MyClass 测试的输出结果是:
10
20
100
100
具体的原因相信经过大家的分析应该会很清楚的。另外如果大家有兴趣可以用 structs 再试试,也可以同时对 structs 在 C++ 和 C# 中的区别有进一步的认识。
页:
[1]
