带有 ref 的扩展方法不适用于数组
Extension method with ref does not work with arrays
我写了这段代码:
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
实际上是一个数组,但这有什么区别呢?是不是数组默认按引用传递,所以无效?
是否有任何我可以编写的不会产生错误的等效语句?
哎呀,很抱歉提出所有问题。谢谢。
因为数组是引用类型
因此,您所拥有的是对数组的引用,该数组包含对包含结构的数组的其他引用。仅仅因为数组的内容是一个结构并不意味着数组本身就是。
传递数组时不需要使用 ref(只要您只更改内容而不是引用),因为如前所述,它们是reference-types。这意味着如果您简单地删除 ref 关键字,此函数应该具有您想要的确切行为。
现在我相信这应该可以帮助您解决错误。但是我没有说明为什么你不能对 extension-methods 使用 ref,同时 已经发布了,所以也去看看吧:)
编辑:
只是我想补充的东西。你真的不需要再次 return 数组,因为你所做的只是改变 inside 的东西(毕竟,它只是一个参考,所以这些改变在你没有再次 return 数组)。
如果您有以下任一情况,您会想要 return 它:
一个。更改当前范围内的引用并且不使用 ref 关键字
b.即使您使用引用类型来创建一些语法糖(类似于 app.UseX().UseY().UseZ()
的语法),您也希望将调用串在一起。
ref
必须在方法声明和调用时指定。
如果扩展的 this
参数可以通过引用传递,则在调用该方法时将无法指定它。
someObject.CallSomeExtensionMethod();
我们将 ref
放在哪里?无处可去。
如果我们可以通过引用传递一个值而不知道我们正在通过引用传递它,那么奇怪的事情可能会发生。调用修改作为第一个参数传递的值的扩展方法是正常的。例如,我们可以编写一个扩展方法来打乱列表:
list.Shuffle();
我们希望修改列表。但是想象一下,如果扩展方法实际上导致 list
指向 List
的一个完全不同的实例,我们会感到惊讶。即使我们知道它正在发生,那也会很奇怪,但如果这种行为不明确,那将是混乱的。我们可以调用一个不是 ref
的扩展,有人可以将其更改为 ref
而不会破坏任何东西,引入各种疯狂的、不可预测的效果。
在方法和使用它的地方都有 ref
就像一个合同 - 该方法告诉我们它可以替换我们的引用,并且我们给予它明确的许可。
我写了这段代码:
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
实际上是一个数组,但这有什么区别呢?是不是数组默认按引用传递,所以无效?
是否有任何我可以编写的不会产生错误的等效语句?
哎呀,很抱歉提出所有问题。谢谢。
因为数组是引用类型
因此,您所拥有的是对数组的引用,该数组包含对包含结构的数组的其他引用。仅仅因为数组的内容是一个结构并不意味着数组本身就是。
传递数组时不需要使用 ref(只要您只更改内容而不是引用),因为如前所述,它们是reference-types。这意味着如果您简单地删除 ref 关键字,此函数应该具有您想要的确切行为。
现在我相信这应该可以帮助您解决错误。但是我没有说明为什么你不能对 extension-methods 使用 ref,同时
编辑:
只是我想补充的东西。你真的不需要再次 return 数组,因为你所做的只是改变 inside 的东西(毕竟,它只是一个参考,所以这些改变在你没有再次 return 数组)。
如果您有以下任一情况,您会想要 return 它:
一个。更改当前范围内的引用并且不使用 ref 关键字
b.即使您使用引用类型来创建一些语法糖(类似于 app.UseX().UseY().UseZ()
的语法),您也希望将调用串在一起。
ref
必须在方法声明和调用时指定。
如果扩展的 this
参数可以通过引用传递,则在调用该方法时将无法指定它。
someObject.CallSomeExtensionMethod();
我们将 ref
放在哪里?无处可去。
如果我们可以通过引用传递一个值而不知道我们正在通过引用传递它,那么奇怪的事情可能会发生。调用修改作为第一个参数传递的值的扩展方法是正常的。例如,我们可以编写一个扩展方法来打乱列表:
list.Shuffle();
我们希望修改列表。但是想象一下,如果扩展方法实际上导致 list
指向 List
的一个完全不同的实例,我们会感到惊讶。即使我们知道它正在发生,那也会很奇怪,但如果这种行为不明确,那将是混乱的。我们可以调用一个不是 ref
的扩展,有人可以将其更改为 ref
而不会破坏任何东西,引入各种疯狂的、不可预测的效果。
在方法和使用它的地方都有 ref
就像一个合同 - 该方法告诉我们它可以替换我们的引用,并且我们给予它明确的许可。