【问题标题】:Can I pass primitive types by reference in C#?我可以在 C# 中通过引用传递原始类型吗?
【发布时间】:2011-08-19 13:17:04
【问题描述】:

我知道复杂类型在 C# 中通过引用传递,而原始类型通过值传递。我可以在 C# 中通过引用传递原始类型吗?

更新:

感谢您的回答,但我的例子是?

void test(object x) {

}

long y = 1;

test(ref y);

这会抛出这个异常:“ref”参数类型与参数类型不匹配

【问题讨论】:

  • 原始和复杂在这里不是正确的术语。您在谈论值类型和引用类型。
  • 你需要有void test (ref object x),因为ref需要在方法定义和用法中都使用
  • “复杂类型”不是通过引用传递的。除非您使用 ref 或 out 关键字,否则所有类型都按值传递。
  • 函数定义和函数调用都需要ref

标签: c# .net


【解决方案1】:

这里有几个不同的问题。

我可以在 C# 中通过引用传递原始类型吗?

首先,让我们确保这里的行话是正确的。目前尚不清楚您所说的“原始类型”是什么意思。您是指像 int 或 long 这样的“内置于运行时”类型吗?您的意思是任何值类型,无论是内置的还是用户定义的?

我会假设你的问题实际上是

我可以在 C# 中通过引用传递值类型吗?

值类型被称为值类型,因为它们是按值传递的。引用类型之所以称为引用类型,是因为它们是通过引用传递的。因此,根据定义,答案似乎是不。

但是,它并不是那么简单。

首先,您可以通过装箱将值类型的实例转换为引用类型的实例:

decimal d = 123.4m; // 128 bit immutable decimal structure
object o1 = d; // 32/64 bit reference to 128 bit decimal
object o2 = o1; // refers to the same decimal
M(o2); // passes a reference to the decimal.
o2 = 456.78m; // does NOT change d or o1

其次,可以通过制作数组将值类型的实例转为引用:

decimal[] ds1 = new decimal[1] { 123.4m }; 
decimal[] ds2 = ds1;
ds2[0] = 456.7m; // does change ds1[0]; ds1 and ds2 refer to the same array

第三,您可以使用“ref”关键字传递对变量(不是值——变量)的引用:

decimal d = 123.4m;
M(ref d);
...
void M(ref decimal x)
{ // x and d refer to the same variable now; a change to one changes the other

尝试将 ref long 传递给采用 ref 对象的方法会导致编译错误:“ref”参数类型与参数类型不匹配

正确。两边的变量类型必须完全匹配。有关详细信息,请参阅此问题:

Why doesn't 'ref' and 'out' support polymorphism?

【讨论】:

    【解决方案2】:

    当然可以:

    public void MyFunction(ref int a)
    {
    }
    

    【讨论】:

    【解决方案3】:

    只需使用refout 参数修饰符即可。

    void myMethod(ref int myValue) ...
    

    ref 是 2 路。 out 是一种方式。

    【讨论】:

      【解决方案4】:

      您可以在函数定义中的参数旁边使用ref 字。

      public void func(ref int a)
      {
          //do stuff
      }
      
      public void doStuf()
      {
          int a = 5;
          func(ref a);
      }
      

      【讨论】:

      • 糟糕,看来每个人都击败了我。
      • 要记住的重要规则是变量必须以ref 形式传递
      【解决方案5】:

      更新后您可以通过引用传递盒装值

      static void Main(string[] args)
      {
          var value = 10;
          var boxed = (object)value;
          TakesValueByRef(ref boxed);
          value = (int)boxed;
          // value now contains 5.
      }
      
      static void TakesValueByRef(ref object value)
      {
          value = 5;
      }
      

      请记住,这是一种糟糕的做法,并且这样做是有风险的(由于强制转换异常)。

      【讨论】:

      • 这个例子与上面的评论不符。您通过 ref 传递,因为您使用了 'ref' 关键字。这与拳击无关。您可以通过转换为 object 或仅使用 ref 关键字将其装箱,您不需要同时进行。
      • @justin.m.chase 首先在 IDE 中尝试您的理论。如果你看他的问题,他想要一个对象参数;这涉及到装箱,这意味着您需要一个装箱的值才能将其传递给函数。
      • @johnathan:他的问题在代码和术语中有很多错误。首先,他的代码甚至无法编译。老实说,我什至不明白你的反应。您不需要装箱即可通过引用传递值类型。就是这么简单。试试“void test(ref long value) { value = 5; }”你会看到的。
      • @justin.m.chase 如果方法需要对象参数,您需要将其装箱。
      • @justin.m.chase 我觉得你会批评一个你明确表示你不理解的答案很有趣。你用这个让我很开心。
      【解决方案6】:

      您正在混合概念。默认的参数传递约定是按值。您可以将引用类型对象传递给方法或将值类型对象传递给方法。您通过使用 变量 传递对象。该变量是按值传递的。在方法内部,参数是您传递的变量的副本

      如果你用refout装饰参数,那么改变你内部的方法也会影响传递的变量。

      // Doesn't change obj1
      void DoesntChange(object obj)
      {
          obj = new object(); // Assigns a new object to the local variable obj.
      }
      
      var obj1 = new object();
      DoesntChange(obj1);
      
      // Will change obj2
      void WillChange(ref object obj)
      {
          obj = new object(); // Assigns a new object to the local ref variable obj
                              // and changes the obj2 variable to point at the new object.
      }
      
      var obj2 = new object();
      WillChange(ref obj2);
      

      要在方法中改变原始类型变量参数并在调用站点保持更改,它必须由refout 传递。

      【讨论】:

        猜你喜欢
        • 2011-04-09
        • 2023-03-22
        • 2015-02-22
        • 2011-05-18
        • 2015-09-15
        • 2014-08-22
        • 1970-01-01
        • 2020-09-08
        相关资源
        最近更新 更多