簡體   English   中英

為什么在C#中引用和退出?

[英]Why ref and out in C#?

使用關鍵字ref ,調用代碼需要初始化傳遞的參數,但是使用關鍵字out我們不需要這樣做。

  • 為什么我們out到處都用?
  • 這兩者之間有什么區別?
  • 請舉例說明我們需要使用ref並且不能使用的out

答案在這篇MSDN文章中給出。 從那篇文章:

outref尋址的兩個參數傳遞模式略有不同,但它們都非常常見。 這些模式之間的細微差別導致一些非常常見的編程錯誤。 這些包括:

  1. 不為所有控制流路徑中的out參數賦值
  2. 不將值賦給用作ref參數的變量

因為C#語言為這些不同的參數傳遞模式分配了不同的明確賦值規則,所以這些常見的編碼錯誤被編譯器捕獲為不正確的C#代碼。

決定包括refout參數傳遞模式的關鍵是允許編譯器檢測這些常見的編碼錯誤值得在語言中同時具有refout參數傳遞模式的額外復雜性。

out是一種特殊形式的ref ,其中引用的內存不應在調用之前初始化。

在這種情況下,C#編譯器強制在方法返回之前分配out變量,並且在分配變量之前不使用該變量。

兩個例子,其中out不工作,但ref的作用:

void NoOp(out int value) // value must be assigned before method returns
{
}

void Increment(out int value) // value cannot be used before it has been assigned
{
    value = value + 1;
}

這些答案都不能讓我滿意,所以這里是我采取的refout

我的回答是以下兩頁的摘要:

  1. ref(C#參考)
  2. out(C#參考)

相比

  1. 方法定義和調用方法都必須明確使用ref / out關鍵字
  2. 兩個關鍵字都會導致參數通過引用傳遞( 偶數值類型
  3. 但是,通過引用傳遞值類型時沒有裝箱
  4. 屬性不能通過outref傳遞,因為屬性確實是方法
  5. ref / out在編譯時不被視為方法簽名的一部分,因此如果方法之間的唯一區別是其中一個方法采用ref參數而另一個方法采用out參數,則方法不能重載

對比

ref

  1. 必須在傳遞之前進行初始化
  2. 可以用來將值傳遞給方法

out

  1. 在傳遞之前不必初始化
  2. 在方法返回之前,需要調用方法來指定值
  3. 不能用於將值傳遞給方法

例子

不會編譯,因為只有方法簽名的差異是ref / out

public void Add(out int i) { }
public void Add(ref int i) { }

使用ref關鍵字:

public void PrintNames(List<string> names)
{
  int index = 0; // initialize first (#1)

  foreach(string name in names)
  {
    IncrementIndex(ref index);
    Console.WriteLine(index.ToString() + ". " + name);
  }
}

public void IncrementIndex(ref int index)
{
  index++; // initial value was passed in (#2)
}

使用out關鍵字:

public void PrintNames(List<string> names)
{
  foreach(string name in names)
  {
    int index; // not initialized (#1)

    GetIndex(out index);
    Console.WriteLine(index.ToString() + ". " + name);
  }
}

public void GetIndex(out int index)
{
  index = IndexHelper.GetLatestIndex(); // needs to be assigned a value (#2 & #3)
}

作者的隨機評論

  1. 在我看來,使用out關鍵字的概念類似於使用ParameterDirectionOutput枚舉值在ADO.NET中聲明輸出參數
  2. C#中的數組通過引用傳遞,但是為了重新分配數組引用以影響調用代碼中的ref必須使用ref關鍵字

例:

public void ReassignArray(ref int[] array)
{
  array = new int[10]; // now the array in the calling code
                       // will point to this new object
}

有關引用類型與值類型的更多信息,請參閱傳遞引用類型參數(C#編程指南)

一個人為的例子,當你需要使用ref而不是out時,如下:

public void SquareThisNumber(ref int number) 
{
   number = number * number;
}

int number = 4;
SquareThisNumber(ref number);

這里我們希望number是一個in-out變量,所以我們使用ref 如果我們用完out ,編譯器會給出一個錯誤,說我們在使用之前初始化了一個out參數。

ref關鍵字允許您更改參數的值。 被調用的方法可以是調用鏈中的中間鏈接。 使用out關鍵字的方法只能在調用鏈的開頭使用。

另一個優點是現有值可以用在方法的邏輯中並且仍然保持返回值。

在Oracle函數中有明確的IN(默認和你沒有設置方向時得到的)IN / OUT和OUT參數。 等效是正常的(只是參數),ref [參數]和out [參數]。

編譯器知道在調用之前不應設置out變量。 這允許它們在使用前聲明。 但是它知道它必須在返回時使用的函數之前設置。

當我們在調用以out關鍵字為前綴的方法時傳遞值時,它會將它視為完全不同,就像我們沒有將它傳遞給方法一樣。 相反,我們實際上是將out變量的值從方法的定義部分收集(outing)到我們調用該方法的method out變量參數。

因此out variable是在方法定義中完成的處理輸出,這就是我們需要創建它,初始化它並僅在定義中修改它的原因。

當我們需要從特定方法返回多個值時,使用out變量。

ref變量的情況下,我們需要首先初始化它,因為它的內存位置被轉換為方法定義作為參數。 想想如果我們在傳遞之前沒有初始化會發生什么?

暫無
暫無

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

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