为啥 ref 参数类型与常规类型不同?

Posted

技术标签:

【中文标题】为啥 ref 参数类型与常规类型不同?【英文标题】:Why is a ref parameter type different to the regular type?为什么 ref 参数类型与常规类型不同? 【发布时间】:2012-02-12 02:58:25 【问题描述】:

我了解如何在两种不同类型之间进行切换,但我的问题是;为什么这种差异在类型级别

我原以为它是ParamterInfo 对象的属性,而不是单独的特殊类型。

假设它在反射中作为一个单独的类型呈现,因为它在内部就是这样,将它作为一个单独的类型有什么语言好处(我猜是更容易的方法重载解析或其他东西)?

在类似的说明中,为什么ref 是一个独特的类型而out 不是(我想不出ref 是一个单独的类型的原因,这不适用于out )?

【问题讨论】:

【参考方案1】:

ref 参数具有不同的类型,因为ref 类型在参数以外的其他上下文中也是允许和有用的。 C# 不允许,但其他语言(至少 C++/CLI)确实支持,例如,引用类型的局部变量。这样的事情对ref 有意义,但对out 没有意义。

假装C#允许,你可以写(IL支持):

int x = 3;
ref int y = x;
y = 4;
if (x == 4)
    MessageBox.Show("x is 4");

这不是一个有用的例子,但在ref参数有用的相同情况下,使用带有@987654327的辅助类或结构也很有用@字段。

【讨论】:

啊,有道理。一个例子会有所帮助。我看不出你会如何使用 ref local。 更新了一个毫无用处的例子:) 啊,我明白了,但仍然不太确定实际的应用程序。猜猜你可能有 y 指几个变量或某事之一(或数组中的元素?)。 另一件事是,ref 对互操作很有用,因为 ref 在非托管代码中传递时将表现为指针。另一方面,out 不能与互操作一起使用。 一个 ref return type 函数的示例,即使您无法在 C# 中自己定义它,C# 也会使用它是数组上的 Address 函数,它允许您使用多维数组元素的地址(为了传递给 ref 参数)。【参考方案2】:
public static int SomeMethod(string local, ref string strParam)

  local = SomeStaticlyHeldString;
  strParam = SomeStaticlyHeldString;
  int localInt = local.Length;
  return strParam.Length;

local 的赋值意味着local 标记的内存位置现在指向SomeStaticlyHeldString 指向的同一个对象。

strParam 的赋值意味着参数传递给使用ref 标签的方法的内存位置现在指向SomeStaticlyHeldString 指向的同一个对象。

获取local.Length查询local指向的对象。获取strParam.Length查询strParam所指向的变量,所指向的对象。

两者的行为确实非常不同,不仅仅是在定义参数或本地时,而是在每次使用它们时。差异在很大程度上是隐藏的,这使得它们更加不同,因为对它们的每次操作在效果上都不同。

如果我们有一个只有局部变量、某种非局部堆上的对象以及指向这两者的指针的低级语言,那么local 的类型将是string*strParam输入string**。这将是我们如何在 C 中进行类似的操作,以及我们如何在 C++ 中这样做,尽管它也有引用类型(尽管在 C++ 中,类型是引用类型更清楚地是其类型定义的一部分,并且它们有进一步的用途和改进)。 C# 在其语法中几乎对我们隐藏了所有这些内容。任何隐藏细节的好处总是值得商榷,但在这种情况下,隐藏任何有用的东西并没有太多好处,因此很难批评它。

【讨论】:

接受这个作为 IMO 可以更好地回答我的问题。谢谢。 :)

以上是关于为啥 ref 参数类型与常规类型不同?的主要内容,如果未能解决你的问题,请参考以下文章

Blazor - SetParameters - 为啥字符串参数绑定的行为与复杂类型不同

将 ref 关键字与引用类型参数一起使用有啥好处?

为啥我不能用相同的参数类型组合两个不同的函数?

为啥将自定义 WrappedRequest 与额外的类型参数和 ActionFilter 组合会导致类型丢失?

vue3+ts 中 ref与reactive 如何指定类型

为啥没有为不同的返回类型定义方法重载?