带有ref的扩展方法不适用于数组

时间:2019-06-06 21:42:12

标签: c# generics extension-methods

我写了这段代码:

public static T[][] Populate<T>(this ref T[][] arg, T with) where T : struct
{
    for (int i = 0; i < arg.Length; i++)
    {
        for (int j = 0; j < arg[i].Length; j++)
        {
            arg[i][j] = with;
        }
    }
    return arg;
}

然后出现以下错误:

error 为什么不起作用?将this带走后,类似的情况会起作用,不是吗?而且似乎满足了这些限制:我指定的T必须是struct;我知道arg实际上是一个数组,但这有什么区别?数组是否默认通过引用传递,所以无效?

我是否可以编写不会产生错误的等效语句?

Ph,对于所有问题,我们深表歉意。谢谢。

2 个答案:

答案 0 :(得分:4)

ref必须在方法声明中以及在调用方法时都指定。

如果扩展名的this参数可以通过引用传递,则在调用该方法时将无法指定它。

someObject.CallSomeExtensionMethod();

我们将ref放在哪里?无处。

如果我们可以在没有知道的情况下通过引用传递值,那么可能会发生奇怪的事情。调用扩展方法来修改作为第一个参数传递的值是正常的。例如,我们可以编写一个扩展方法来随机播放列表:

list.Shuffle();

我们希望列表会被修改。但是,如果扩展方法实际上导致list指向List的完全不同的实例,我们会感到惊讶。即使我们知道发生的事情也很奇怪,但是如果这种行为不明确,那就太混乱了。我们可以称呼不是ref的扩展名,有人可以将其更改为ref而不会破坏任何东西,从而引入各种疯狂的,不可预测的效果。

方法和用法中都ref就像合同一样-该方法告诉我们它可以代替我们的引用,并且我们给予它明确的许可。

答案 1 :(得分:1)

这是因为数组是引用类型。
因此,您所拥有的是对包含其他引用的包含结构的数组的引用。仅仅因为数组的内容是一个结构并不意味着数组本身就是结构。

传递数组时不需要使用ref(,只要您仅更改内容而不是引用即可),因为如上所述,它们是引用类型。这意味着,如果仅删除ref关键字,则此函数应具有所需的确切行为。

现在,我相信这应该可以帮助您解决错误。但是,我没有说明为什么不能将ref用作扩展方法,而与此同时a really good explanation也已经发布,所以也请检查一下:)

修改:
只是我想添加的内容。您实际上并不需要再次返回该数组,因为您所做的只是在其内部 进行了更改(毕竟,这只是一个参考,因此这些更改都可以进行,而无需再次返回该数组)。

如果您愿意,可以退回它:

a。在当前作用域中更改引用,并且不使用ref关键字
 b。即使您使用引用类型来创建一些语法糖(如app.UseX().UseY().UseZ()这样的语法),也希望将调用串在一起。