共用方式為


"基於模式的使用" 和 "使用宣告"

注意

本文是功能規格。 規格可作為功能的設計檔。 其中包含建議的規格變更,以及功能設計和開發期間所需的資訊。 這些文章會發佈,直到提議的規格變更完成並併併入目前的ECMA規格為止。

功能規格與已完成實作之間可能有一些差異。 這些差異是在 語言設計會議(LDM)筆記中擷取的。

您可以在 規格的文章中深入了解將功能規範採納為 C# 語言標準的過程

冠軍問題:https://github.com/dotnet/csharplang/issues/114

總結

語言會在 using 語句周圍新增兩項新功能,讓資源管理更簡單:除了 using 之外,IDisposable 應該辨識可處置模式,並將 using 宣告新增至語言。

動機

using 聲明是當今資源管理的有效工具,但它需要相當多的儀式。 具有許多資源需管理的方法,可能會因為一連串的 using 語句而在語法上變得繁複。 此語法負擔大到讓大部分的編碼樣式指導方針針對大括號在這種情況下明確設有例外。

using 宣告會移除這裡的絕大部分繁瑣,使 C# 更接近於那些包含資源管理區塊的其他語言。 此外,模式型 using 可讓開發人員擴充可在這裡參與的類型集合。 在許多情況下,可取消建立只為了在 using 語句中使用值的包裝類型的需求。

這些功能一起可讓開發人員簡化和擴充可套用 using 的案例。

詳細設計

使用宣告

語言將允許將 using 新增至局部變數宣告。 這類宣告的效果會與在相同位置的 using 語句中宣告變數相同。

if (...) 
{ 
   using FileStream f = new FileStream(@"C:\source\using.md");
   // statements
}

// Equivalent to 
if (...) 
{ 
   using (FileStream f = new FileStream(@"C:\source\using.md")) 
   {
    // statements
   }
}

using 本地變數的存續時間會延伸到其被宣告的範圍結尾。 然後,會以宣告局部變數的反向順序處置 using 局部變數。

{ 
    using var f1 = new FileStream("...");
    using var f2 = new FileStream("...");
    using var f3 = new FileStream("...");
    ...
    // Dispose f3
    // Dispose f2 
    // Dispose f1
}

goto 宣告下,using或任何其他控制流程結構都沒有任何限制。 相反,程式碼的行為就像等效的 using 語句一樣。

{
    using var f1 = new FileStream("...");
  target:
    using var f2 = new FileStream("...");
    if (someCondition) 
    {
        // Causes f2 to be disposed but has no effect on f1
        goto target;
    }
}

using 本機宣告中定義的變數將會隱含為唯讀。 這符合在 using 語句中宣告的局部變數行為。

using 宣告的語言文法如下:

local-using-declaration:
  'using' type using-declarators

using-declarators:
  using-declarator
  using-declarators , using-declarator
  
using-declarator:
  identifier = expression

using 宣告的限制:

  • 可能不會直接出現在 case 標籤,但必須位於 case 卷標內的區塊內。
  • 可能不會顯示為 out 變數宣告的一部分。
  • 每個宣告項都必須有初始化器。
  • 本機類型必須能被隱式轉換為 IDisposable 或滿足 using 模式。

以模式為基礎的應用

語言會新增 ref struct 類型的可處置模式概念:這是具有可存取 ref struct 實例方法的 Dispose。 符合可處置模式的類型可以參與 using 語句或宣告,而不需要實作 IDisposable

ref struct Resource
{ 
    public void Dispose() { ... }
}

using (var r = new Resource())
{
    // statements
}

這可讓開發人員利用 using 來處理 ref struct 類型。 這些類型無法在 C# 8 中實作介面,因此無法參與 using 語句。

傳統 using 語句的限制同樣適用於此:在 using 中宣告的局部變數是唯讀的,null 值不會引發例外狀況。程式碼生成的不同之處在於,呼叫 Dispose 之前不會轉換成 IDisposable

{
	  Resource r = new Resource();
	  try {
		    // statements
	  }
	  finally {
		    if (r != null) r.Dispose();
	  }
}

為了符合可處置模式,Dispose 方法必須是可存取的實例成員、無參數且具有 void 傳回類型。 它不能是擴充方法。

注意事項

這些考慮都未在 C# 8 中實作

沒有區塊的案例標籤

由於其實際存留期的複雜性,using declarationcase 標籤內直接使用是非法的。 為其設定與同一位置的 out var 相同的存留期是一個潛在的解決方案。 被認為功能實作的額外複雜性和工作的簡便替代方法(只需在 case 標籤中新增一個區塊)都不足以證明走這條路線的合理性。

未來擴張

固定局部變數

fixed 語句具有 using 語句的所有屬性,其動機是擁有 using 局部變數的能力。 應考慮將這項功能延伸至 fixed 局部變數。 存留期和排序規則應該同樣適用於此處的 usingfixed