有很多例子,让我们以数组复制方法为例。 Array.Copy is方法的签名如下
public static void Copy (Array sourceArray, long sourceIndex, Array destinationArray, long destinationIndex, long length);
仅从签名来看,不能说sourceArray不会更改,而destinationArray会更改,即使它像Int数组那样简单。 程序员对关键字“ ref”的保证在这里已经失去。
在我看来,最好将destinationArray参数标记为“ ref Array”。如果以此方式完成,语法将与关键字“ ref”的用法更加一致,表明被传入的对象可能会修改传入的对象,并且该更改对于调用者是可见的。我可以想到的关于简化关键字“ ref”的唯一好处是可以节省一些按键。还是只是在模仿C / C ++样式而没有太多思考。
我的问题是:这个设计决定背后有哪些调味料?
更新:为了便于记录,我提倡一个数组与其元素具有相同的值/引用类别,从而使Fun(array)和Fun(ref array)之间明确消失,这是程序员的相同保证。获得Fun(int)和Fun(ref int)。效率的优化可以留给实施级别。
答案 0 :(得分:4)
数组是引用类型。您可以按值传递引用,它们引用的实例仍将与被修改的实例相同。被调用者正在使用其自己的引用来修改同一实例,而没有理由将其完全更改为完全不同的实例(这实际上是ref
的使用位置。)
没有任何约定规定在传递引用类型时使用ref
-通常不需要大部分时间,除非有提到,如果您的方法实际上打算像这样完全更改实例, :
class Foo { public int Value; }
public static void ReplaceFoo(ref Foo foo)
{
foo = new Foo { Value = 2 };
}
var foo = new Foo { Value = 1 };
Console.WriteLine(foo.Value);
ReplaceFoo(ref foo);
Console.WriteLine(foo.Value);
仅从签名来看,不能说sourceArray不会更改,而destinationArray会更改
为什么这是个问题?没有人会仅在关注方法签名而忽略参数名称的情况下读取API。签名供编译器用来区分重载。凡是阅读Array.Copy()
的API的人都会理解,sourceArray
将保持不变,因为该方法从那里获取值,而destinationArray
将被修改,成为接收该方法的对象。值-除非它们不会说英语(可以,但是大多数API用英语编写)。
我能想到的唯一的其他情况是读者是否会困惑,如果他们没有先验知识,即数组是.NET中的引用类型。但是在充其量的情况下误用ref
并不能解决该问题。
答案 1 :(得分:0)
C#(和.NET)包括引用类型和值类型。
通常(缺少ref
或out
关键字)将参数传递给方法by value
。因此,如果将整数传递给函数,则将传递整数值。如果在函数调用中放置一个引用数组的变量(请记住所有数组都是引用类型System.Array的实例),则该变量的值(即对该数组的引用)将传递给该函数。
因此,在函数内,代码将在该数组上播放。当函数返回时,该变量(在调用者的范围内)仍引用同一对象。但是,该函数可能对该数组进行了 mutt 修改,因此变量(在调用方作用域中)可能引用更改的对象。
如果通过引用传递值类型(使用ref
关键字),则该函数可以更改参数的值,并且当函数返回时,该变量(在调用方作用域中)将收到新的值。
但是,如果您在引用类型的参数上使用ref
(或out
),则会通过引用传递引用。。因此,例如,您可以传入五个整数的数组,并且该函数可以分配该参数和十个整数的数组(它们的类型相同,但对象肯定不同)。在调用方中,当函数返回时,与该参数关联的变量将在调用过程中看到其所指的内容完全更改。
在您的示例中,调用方将实例化两个具有相同类型和兼容长度的数组(如果源索引和目标索引为0并且长度为sourceArray.Length
,则通常为相同长度)。该函数不会更改目标数组参数所指向的对象,而只是从源中填充目标。
实际上,如果目的地是by ref
,它将不会那么灵活。考虑一个目标的长度为30个条目的情况,而您的意图是用源填充中间的十个数组条目。它只是工作。不会带有ref
目标参数(无需进行更多工作)。
答案 2 :(得分:-1)
省略ref关键字的原因是,在大多数情况下,将其包括在内不会有任何区别,因此是多余的。但是,实际上在某些情况下确实有所不同。数组是引用类型,表示表示该引用的值已传递。通常,更新传入的值将触发对原始对象的更新。但是,如果您创建一个NEW数组并将传入的参数分配给新项目,则引用将丢失-而ref关键字将其保留。