"基于模式使用" 和 "using 声明""pattern-based using" and "using declarations"
总结Summary
语言将添加两个新功能 using
来使资源管理更简单: using
应识别一种可释放模式 IDisposable
,并向 using
语言添加声明。The language will add two new capabilities around the using
statement in order to make resource management simpler: using
should recognize a disposable pattern in addition to IDisposable
and add a using
declaration to the language.
动机Motivation
该 using
语句是当今资源管理的有效工具,但它需要很多工作。The using
statement is an effective tool for resource management today but it requires quite a bit of ceremony. 具有多个要管理的资源的方法可以从语法上陷入一系列 using
语句。Methods that have a number of resources to manage can get syntactically bogged down with a series of using
statements. 这种语法负担足以表明,大多数编码样式准则对此方案在大括号附近有一个例外。This syntax burden is enough that most coding style guidelines explicitly have an exception around braces for this scenario.
此 using
声明消除了这里的许多仪式,并与包含资源管理块的其他语言一起获取了 c #。The using
declaration removes much of the ceremony here and gets C# on par with other languages that include resource management blocks. 此外,基于模式的 using
允许开发人员展开可参与的类型集。Additionally the pattern-based using
lets developers expand the set of types that can participate here. 在许多情况下,无需创建仅存在的包装类型,就可以在语句中使用值 using
。In many cases removing the need to create wrapper types that only exist to allow for a values use in a using
statement.
借助这些功能,开发人员可简化和扩展 using
可应用的方案。Together these features allow developers to simplify and expand the scenarios where using
can be applied.
详细设计Detailed Design
using 声明using declaration
语言将允许 using
添加到局部变量声明。The language will allow for using
to be added to a local variable declaration. 此类声明与在同一位置的语句中声明变量的效果相同 using
。Such a declaration will have the same effect as declaring the variable in a using
statement at the same location.
if (...)
{
using FileStream f = new FileStream(@"C:\users\jaredpar\using.md");
// statements
}
// Equivalent to
if (...)
{
using (FileStream f = new FileStream(@"C:\users\jaredpar\using.md"))
{
// statements
}
}
本地的生存期 using
将扩展到声明它的范围的末尾。The lifetime of a using
local will extend to the end of the scope in which it is declared. 然后,将 using
按声明的反向顺序来处理局部变量。The using
locals will then be disposed in the reverse order in which they are declared.
{
using var f1 = new FileStream("...");
using var f2 = new FileStream("..."), f3 = new FileStream("...");
...
// Dispose f3
// Dispose f2
// Dispose f1
}
goto
在声明中没有围绕或任何其他控制流构造的限制 using
。There are no restrictions around goto
, or any other control flow construct in the face of a using
declaration. 相反,代码的行为与对等效语句的行为一样 using
:Instead the code acts just as it would for the equivalent using
statement:
{
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
将隐式为只读。A local declared in a using
local declaration will be implicitly read-only. 这与语句中声明的局部变量的行为匹配 using
。This matches the behavior of locals declared in a using
statement.
声明的语言语法 using
如下:The language grammar for using
declarations will be the following:
local-using-declaration:
using type using-declarators
using-declarators:
using-declarator
using-declarators , using-declarator
using-declarator:
identifier = expression
关于声明的限制 using
:Restrictions around using
declaration:
- 不能直接显示在标签
case
内,而是必须位于标签内的 块case
内。May not appear directly inside acase
label but instead must be within a block inside thecase
label. - 可能不会显示为变量声明的
out
一部分。May not appear as part of anout
variable declaration. - 每个声明符必须具有初始值设置项。Must have an initializer for each declarator.
- 本地类型必须可隐式转换为
IDisposable
或满足using
模式。The local type must be implicitly convertible toIDisposable
or fulfill theusing
pattern.
使用基于模式的pattern-based using
语言将添加可释放模式的概念:即具有可访问实例方法 Dispose
的类型。The language will add the notion of a disposable pattern: that is a type which has an accessible Dispose
instance method. 适合可释放模式的类型可以参与语句或 using
声明,而无需实现 IDisposable
。Types which fit the disposable pattern can participate in a using
statement or declaration without being required to implement IDisposable
.
class Resource
{
public void Dispose() { ... }
}
using (var r = new Resource())
{
// statements
}
这使开发人员能够 using
利用许多新方案:This will allow developers to leverage using
in a number of new scenarios:
ref struct
:这些类型目前无法实现接口,因此不能参与using
语句。ref struct
: These types can't implement interfaces today and hence can't participate inusing
statements.- 扩展方法将使开发人员能够增强其他程序集中的类型以参与
using
语句。Extension methods will allow developers to augment types in other assemblies to participate inusing
statements.
如果类型可以隐式转换为 并且也适合可释放模式, IDisposable
则 IDisposable
为首选。In the situation where a type can be implicitly converted to IDisposable
and also fits the disposable pattern, then IDisposable
will be preferred. 尽管此方法采用与接口 (相反的方法,但) foreach
向后兼容性是必需的。While this takes the opposite approach of foreach
(pattern preferred over interface) it is necessary for backwards compatibility.
传统语句的相同限制也适用于此处:在 中声明的局部变量是只读的,值不会导致引发异常 using
using
null
,等等。代码生成将有所不同,因为调用 Dispose 之前不会 IDisposable
强制转换到 :The same restrictions from a traditional using
statement apply here as well: local variables declared in the using
are read-only, a null
value will not cause an exception to be thrown, etc ... The code generation will be different only in that there will not be a cast to IDisposable
before calling Dispose:
{
Resource r = new Resource();
try {
// statements
}
finally {
if (r != null) r.Dispose();
}
}
为了适应可释放模式, Dispose
该方法必须可访问、无参数且具有 void
返回类型。In order to fit the disposable pattern the Dispose
method must be accessible, parameterless and have a void
return type. 没有其他限制。There are no other restrictions. 这明确意味着可以在此处使用扩展方法。This explicitly means that extension methods can be used here.
注意事项Considerations
不带块的 case 标签case labels without blocks
直接 using declaration
在标签内部非法 case
,因为在其实际生存期周围出现复杂情况。A using declaration
is illegal directly inside a case
label due to complications around its actual lifetime. 一种可能的解决方案是只为它提供与位于同一 out var
位置的 相同的生存期。One potential solution is to simply give it the same lifetime as an out var
in the same location. 这会被视为功能实现的额外复杂性,并使 (只需将块添加到标签中, case
) 没有采用此路线的理由。It was deemed the extra complexity to the feature implementation and the ease of the work around (just add a block to the case
label) didn't justify taking this route.
未来扩展Future Expansions
固定局部变量fixed locals
fixed
语句包含的所有语句属性都可以 using
具有 using
局部变量。A fixed
statement has all of the properties of using
statements that motivated the ability to have using
locals. 应考虑将此功能扩展到 fixed
局部变量。Consideration should be given to extending this feature to fixed
locals as well. 生存期和顺序规则应该同样适用于 using
和 fixed
此处。The lifetime and ordering rules should apply equally well for using
and fixed
here.