簡體   English   中英

何時將ref參數賦值在C#中有效?

[英]When is assignment to a ref argument effective in C#?

假設一種方法正在更改通過引用傳遞的參數的值。 這樣的操作的效果是在整個應用程序中立即可見還是僅在方法返回后可見?

下面是一個意義重大的示例:

int x = 0;
void Foo(ref int y)
{
    ++y;
    Console.WriteLine(x);
}
Foo(ref x);

它可以在C#Pad中的http://csharppad.com/gist/915318e2cc0da2c2533dfa7983119869下運行

函數Foo可以訪問變量x因為它在同一范圍內,並且恰好在調用站點上接收到對該變量的引用。 如果++y的效果是立即產生的,則輸出應為1 ,但是我可以想象一個編譯器生成的代碼,例如,將本地值存儲在寄存器中,並在返回之前稍后轉儲到內存中。 語言規范是確保輸出為1還是允許抖動優化,從而使輸出實現依賴於語言?

這樣的操作的效果是在整個應用程序中立即可見還是僅在方法返回后可見?

它是立即可見的-因為從根本上講,您最終傳遞的是變量本身,而不是變量的值。 您正在修改完全相同的存儲位置。

確實,您可以在相同的方法中看到此內容:

using System;

class Test
{
    static void Main(string[] args)
    {
        int a = 10;
        Foo(ref a, ref a);
    }

    static void Foo(ref int x, ref int y)
    {
        x = 2;
        Console.WriteLine(y); // Prints 2, because x and y share a storage location
    }
}

這在5.1.5節的C#5規范中:

參考參數不會創建新的存儲位置。 而是,引用參數表示與在函數成員或匿名函數調用中作為參數給出的變量相同的存儲位置。 因此,參考參數的值始終與基礎變量相同。

順便說一句,相反的情況也是如此-如果基礎變量的值以其他方式更改,則該更改將在方法中可見。 使用委托更改值的示例:

using System;

class Test
{
    static void Main(string[] args)
    {
        int a = 10;
        Foo(ref a, () => a++);
    }

    static void Foo(ref int x, Action action)
    {
        Console.WriteLine(x); // 10
        action();             // Changes the value of a
        Console.WriteLine(x); // 11
        x = 5;
        action();
        Console.WriteLine(x); // 6
    }
}

ref是存儲位置的別名 ref參數指向與您傳入的變量完全相同的變量,因此,可以立即看到分配。

C#規范保證在單線程上下文中運行時,必須觀察到所有操作均按順序進行。 因此,對於您提供的程序而言,輸出0將是無效的優化,因為這將導致從單個線程觀察到重新排序。

當您提供ref參數時,最重要的是該參數是所引用變量的別名 它不是副本; 僅在方法完成后才能觀察到更改。 而是,程序中y任何用法在語義上與x相同,因為兩個標識符都引用相同的存儲位置。

我會注意到,您的程序只在使用ref參數的方法返回后才訪問變量,因此它實際上並未回答您的問題。 實際上,根據ref參數實際上是對同一變量的引用還是僅在方法末尾將值復制回來的情​​況,實際發生變化的程序片段如下所示:

public static void Foo(ref int y, Func<int> function)
{
    y = 42;
    Console.WriteLine(function());
}

int x = 7;
Foo(ref x, () => x);

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM