【问题标题】:Extension method with ref does not work with arrays带有 ref 的扩展方法不适用于数组
【发布时间】:2019-06-06 21:42:12
【问题描述】:

我写了这段代码:

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;
}

我收到以下错误:

为什么这不起作用?当this 被带走时,类似的情况也会起作用,不是吗?并且似乎满足了限制:我指定T 必须是struct;我知道arg 确实是一个数组,但这有什么区别呢?是不是数组默认是引用传递,所以无效?

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

唷,抱歉所有问题。谢谢。

【问题讨论】:

  • 数组不是结构体,即使它的成员是结构体。
  • "是不是数组默认按引用传递" 数组和所有类型一样,默认按值传递。类型仅在显式使用 refinout 时通过引用传递。传递的值本身就是对数组等引用类型的引用。但无论是值传递还是引用传递都与你无关,因为你没有改变变量,你只是在使用它的值。

标签: c# generics extension-methods


【解决方案1】:

ref 必须在方法声明和调用时都指定。

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

someObject.CallSomeExtensionMethod();

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

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

list.Shuffle();

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

在方法和使用它的地方都有ref 就像一个合同 - 该方法告诉我们它可以替换我们的引用,并且我们给予它明确的许可。

【讨论】:

    【解决方案2】:

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

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

    现在我相信这应该可以帮助您解决错误。但是我没有说明为什么你不能将 ref 用于扩展方法,同时 a really good explanation 已经发布了,所以也去看看 :)

    编辑:
    只是我想添加的东西。您实际上不需要再次返回数组,因为您所做的只是更改 inside 的内容(毕竟,它只是一个参考,因此这些更改无需再次返回数组即可完成)。

    如果你愿意,你会想要退货:

    一个。更改当前范围内的引用并且不使用 ref 关键字
    湾。即使您使用引用类型来创建一些语法糖(语法如app.UseX().UseY().UseZ()),您仍希望将调用串在一起。

    【讨论】:

    • "传递数组时不需要使用 ref" 不在显示的代码中。如果您希望能够实际更改变量,或者如果在调用方法后观察变量的更改很重要,而不仅仅是访问提供的数组而不期望它在调用中更改,那么您d 需要使用引用参数。
    • 这实际上也没有回答为什么扩展方法的第一个参数不能有 ref 参数的问题。
    • 那么你会如何在这里使用 ref 关键字呢?此外,OP 创建的方法非常基本,不需要 ref 关键字,因为它们使用的是数组。
    • 谢谢。这是否意味着无法在另一个扩展方法中初始化 arg 数组?
    • 我想我不完全理解你的意思,抱歉。正如您的代码将向您展示的那样,如果您不使用 ref 关键字,则填充数组没有问题。您唯一不能做的就是为 arg 分配一个新数组。好吧,您可以,但它只会更改当前方法中的引用,而不是最初传入的引用。
    猜你喜欢
    • 2016-10-07
    • 1970-01-01
    • 2014-08-03
    • 1970-01-01
    • 2019-04-23
    • 2015-12-17
    • 2019-09-23
    • 1970-01-01
    • 2013-09-21
    相关资源
    最近更新 更多