与c#中的值类型和引用类型混淆
我对参数有点困惑。 当我们必须使用引用参数时,何时应该使用c#中的方法/函数编程时使用值类型参数?
您需要非常清楚引用类型与值类型之间的区别,以及“按值”参数与“按引用”参数之间的区别。
我有关于这两个主题的文章:
- 引用类型和值类型
- 参数传递
当使用作为引用类型的“by value”参数时,这两者相互作用:在这种情况下,按值复制的值是引用本身; 您仍然可以修改引用引用的对象:
void SomeMethod(StringBuilder x) { x.Append("Modified"); } ... StringBuilder builder = new StringBuilder(); SomeMethod(builder); Console.WriteLine(builder.ToString()); // Writes "Modified"
请注意,这与传递引用语义不同……如果将SomeMethod
更改为包含:
x = null;
那么这不会使builder
变量为null。 但是,如果您还将 x
参数更改为ref StringBuilder x
(并相应地更改了调用代码),则调用者将看到对x
任何更改(例如将其设置为null)。
在设计自己的API时,我强烈建议您几乎不要使用ref
或out
参数。 它们偶尔会有用,但通常它们表明你试图从单个方法返回多个值,这通常使用专门封装这些值的类型更好,或者如果你使用的话可能是Tuple
类型.NET 4.当然,这条规则有例外,但这是一个很好的起点。
如果使用值类型参数,则无法在方法内更改其值(您可以但这不会反映用于调用方法的变量),而对于引用类型,您可以更改该值。
发送Value类型参数时,内部会将原始变量的副本发送到函数/方法。 因此,如果更改该函数内部的值,则变量的原始值(在声明它的函数中)将保持不变。
发送引用类型参数时,该函数直接使用该变量的原始值。 这是因为您只将该变量的内存引用发送给您的函数。
因此,根据变量的范围以及您希望如何在应用程序中使用该变量,您可以决定如何将其发送到您的函数。 一个很好的例子可能是..如果你想在你的应用程序中计算更新一些全局计数器或状态变量,那么最好通过ref发送它,以便其他函数将在以后获得该变量的最新最新值。
关于这个主题的最佳文章:
.NET中的C#堆(与)堆栈(ing):第一部分
有四个部分。
您可以尝试以下简单代码,我认为它可以帮助您更好地了解何时使用by-reference参数。
using System.Collections.Generic; using System.Diagnostics.Contracts; class Program { static void Main(string[] args) { var list = new List(new[] { 1, 2, 3, 4 }); MakeItNull(list); Contract.Assert(list != null); MakeItRealNull(ref list); Contract.Assert(list == null); } static void MakeItNull(List list) { list = null; } static void MakeItRealNull(ref List list) { list = null; } }