为什么有些C#库函数不';Don’不要遵循;参考「;参数传递约定

为什么有些C#库函数不';Don’不要遵循;参考「;参数传递约定,c#,ref,C#,Ref,有很多例子,让我们以数组复制方法为例。数组的签名。复制方法如下所示 public static void Copy (Array sourceArray, long sourceIndex, Array destinationArray, long destinationIndex, long length); 仅从签名判断,无法判断sourceArray不会更改,而destinationArray会更改,即使是像Int数组这样简单的事情。对于程序员来说,关键字“ref”的保证在这里丢失了。

有很多例子,让我们以数组复制方法为例。数组的签名。复制方法如下所示

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(数组)和Fun(ref数组)之间的区别,这是程序员获得Fun(int)和Fun(ref int)的相同保证。效率的优化可以留待实现级别。

数组是一种参考类型。您可以按值传递引用,它们引用的实例仍将是被修改的实例。被调用方正在使用自己对同一实例的引用来修改该实例,并且没有理由将其完全更改为一个完全不同的实例(这就是
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
并不能解决这个问题。

省略ref关键字的原因是在mos中在t种情况下,包含它不会产生任何影响,因此它是多余的。但是,在某些情况下,它确实会产生影响。数组是引用类型,这意味着会传递一个表示该引用的值。通常,更新传入的值将触发对原始对象的更新。但是如果创建新数组并如果将传入的参数指定给新项,则引用将丢失,而ref关键字将保留它。

C#(和.NET)包括引用类型和值类型

通常(不存在
ref
out
关键字),参数通过值传递给方法
。因此,如果将整数传递给函数,则传递整数的值。如果在函数调用中放入引用数组的变量(记住所有数组都是引用类型System.array的实例),该变量的值,即对数组的引用,被传递给函数

因此,在函数中,代码开始在该数组上运行。当函数返回时,该变量(在调用方作用域中)仍然引用同一对象。但是,函数可能已对该数组进行了变异,因此该变量(在调用方作用域中)可能引用了已更改的对象

如果通过引用传递值类型(使用
ref
关键字),函数可以更改参数的值,并且当函数返回时,变量(在调用者范围内)将接收新值

但是,如果对引用类型的参数使用
ref
(或
out
),则是通过引用传递引用。因此,例如,可以传入五个整数的数组,函数可以指定该参数和十个整数的数组(它们属于相同的类型,但绝对不同的对象)。在调用方中,当函数返回时,与该参数关联的变量将看到它所指的内容在调用过程中完全更改

在您的示例中,调用方将实例化两个类型相同且长度兼容的数组(如果源和目标索引为0且长度为
sourceArray.length
,则通常长度相同)。该函数不更改目标数组参数所指的对象,它只是从源填充目标

实际上,如果Ref目的地是“代码>”,则它不会是灵活的。考虑一个目的地是30个条目长的情况,并且您的意图是用源来填充中间十个数组条目。它只是工作。它不会与<代码> REF目的地参数(没有更多的工作)。< /P>从MSDN引述。“。您也可以使用ref关键字按引用传递引用类型。按引用传递引用类型可使被调用的方法替换调用方中引用参数所引用的对象。对象的存储位置为。”