using
关键字有两个主要用途:
-
作为指令:用于为命名空间创建别名或导入在其他命名空间中定义的类型。
-
作为语句:用于定义一个范围,在此范围的末尾将释放对象。
此外,使用 using 静态指令可定义一种类型,在未指定类型名称的情况下即可访问该类型的静态成员
using
指令有三种用途:
-
允许在命名空间中使用类型,这样无需在该命名空间中限定某个类型的使用:
using System.Text;
-
允许访问类型的静态成员,而无需限定使用类型名称进行访问。
using static System.Math;
-
为命名空间或类型创建别名。 这称为 using 别名指令。
using Project = PC.MyCompany.Project;
using
关键字还用于创建 using 语句,此类语句有助于确保正确处理 IDisposable 对象(如文件和字体)。
Using Static 类型
你可以访问类型的静态成员,而无需限定使用类型名称进行访问:
using static System.Console;
using static System.Math;
class Program
{
static void Main()
{
WriteLine(Sqrt(3*3 + 4*4));
}
}
备注
using
指令的范围限于显示它的文件。
创建 using
别名,以便更易于将标识符限定为命名空间或类型。 using 别名指令的右侧必须始终是一个完全限定类型,而与前面的 using 指令无关。
创建 using
指令,以便在命名空间中使用类型而不必指定命名空间。 using
指令不为你提供对嵌套在指定命名空间中的任何命名空间的访问权限。
命名空间分为两类:用户定义的命名空间和系统定义的命名空间。 用户定义的命名空间是在代码中定义的命名空间。 有关系统定义的命名空间的列表,请参阅 .NET Framework 类库。
示例 1
下面的示例显示如何为命名空间定义和使用 using
别名:
namespace PC
{
// Define an alias for the nested namespace.
using Project = PC.MyCompany.Project;
class A
{
void M()
{
// Use the alias
Project.MyClass mc = new Project.MyClass();
}
}
namespace MyCompany
{
namespace Project
{
public class MyClass { }
}
}
}
using 别名指令的右侧不能有开放式泛型类型。 例如,不能为 List<T> 创建 using 别名,但可以为 List<int> 创建。
示例 2
下面的示例显示如何为类定义 using
指令和 using
别名:
using System;
// Using alias directive for a class.
using AliasToMyClass = NameSpace1.MyClass;
// Using alias directive for a generic class.
using UsingAlias = NameSpace2.MyClass<int>;
namespace NameSpace1
{
public class MyClass
{
public override string ToString()
{
return "You are in NameSpace1.MyClass.";
}
}
}
namespace NameSpace2
{
class MyClass<T>
{
public override string ToString()
{
return "You are in NameSpace2.MyClass.";
}
}
}
namespace NameSpace3
{
// Using directive:
using NameSpace1;
// Using directive:
using NameSpace2;
class MainClass
{
static void Main()
{
AliasToMyClass instance1 = new AliasToMyClass();
Console.WriteLine(instance1);
UsingAlias instance2 = new UsingAlias();
Console.WriteLine(instance2);
}
}
}
// Output:
// You are in NameSpace1.MyClass.
// You are in NameSpace2.MyClass.
using static
指令
指定无需指定类型名称即可访问其静态成员的类型。 语法为:
using static <fully-qualified-type-name>
其中,fully-qualified-type-name 是无需指定类型名称即可访问其静态成员的类型的名称。 如果不提供完全限定的类型名称(完整的命名空间名称以及类型名称),则 C# 将生成编译器错误 CS0246:“找不到‘’的类型或命名空间名称。”
using static
指令适用于任何具有静态成员的类型,即使该类型还具有实例成员。 但是,只能通过类型实例来调用实例成员。
using static
指令是在 C# 6 中引入的。
备注
通常,调用某个静态成员时,即会提供类型名称以及成员名称。 重复输入相同的类型名称来调用该类型的成员将生成详细的晦涩代码。 例如,Circle
类的以下定义引用Math 类的成员数。
using System;
public class Circle
{
public Circle(double radius)
{
Radius = radius;
}
public double Radius { get; set; }
public double Diameter
{
get { return 2 * Radius; }
}
public double Circumference
{
get { return 2 * Radius * Math.PI; }
}
public double Area
{
get { return Math.PI * Math.Pow(Radius, 2); }
}
}
通过消除每次引用成员时,显式引用 Math 类的需求,using static
指令将生成更简洁的代码:
using System;
using static System.Math;
public class Circle
{
public Circle(double radius)
{
Radius = radius;
}
public double Radius { get; set; }
public double Diameter
{
get { return 2 * Radius; }
}
public double Circumference
{
get { return 2 * Radius * PI; }
}
public double Area
{
get { return PI * Pow(Radius, 2); }
}
}
using static
仅导入可访问的静态成员和指定类型中声明的嵌套类型。 不导入继承的成员。 可以从任何带 using static 指令的已命名类型导入,包括 Visual Basic 模块。 如果 F# 顶级函数在元数据中显示为一个已命名类型(其名称是有效的 C# 标识符)的静态成员,则可以导入该 F# 函数。
using static
使指定类型中声明的扩展方法可用于扩展方法查找。 但是,扩展方法的名称不导入到代码中非限定引用的作用域中。
同一编译单元或命名空间中通过不同 using static
命令从不同类型导入的具有相同名称的方法组成一个方法组。 这些方法组内的重载解决方法遵循一般 C# 规则。
示例
以下示例使用 using static
指令来提供 @System.Console、@System.Math 和 String类的静态成员,而无需指定其类型名称。
using System;
using static System.Console;
using static System.Math;
using static System.String;
class Program
{
static void Main()
{
Write("Enter a circle's radius: ");
var input = ReadLine();
if (!IsNullOrEmpty(input) && double.TryParse(input, out var radius)) {
var c = new Circle(radius);
string s = "
Information about the circle:
";
s = s + Format(" Radius: {0:N2}
", c.Radius);
s = s + Format(" Diameter: {0:N2}
", c.Diameter);
s = s + Format(" Circumference: {0:N2}
", c.Circumference);
s = s + Format(" Area: {0:N2}
", c.Area);
WriteLine(s);
}
else {
WriteLine("Invalid input...");
}
}
}
public class Circle
{
public Circle(double radius)
{
Radius = radius;
}
public double Radius { get; set; }
public double Diameter
{
get { return 2 * Radius; }
}
public double Circumference
{
get { return 2 * Radius * PI; }
}
public double Area
{
get { return PI * Pow(Radius, 2); }
}
}
// The example displays the following output:
// Enter a circle's radius: 12.45
//
// Information about the circle:
// Radius: 12.45
// Diameter: 24.90
// Circumference: 78.23
// Area: 486.95
在此示例中,using static
指令也已经应用于 Double 类型。 这使得在未指定类型名称情况下调用 TryParse(String, Double) 方法成为可能。 但是,如此创建的代码可读性较差,因为这样有必要检查 using static
语句,以确定所调用的数值类型的 TryParse
方法。
using 语句
提供可确保正确使用 IDisposable 对象的方便语法。
示例
下面的示例演示如何使用 using 语句。
using (Font font1 = new Font("Arial", 10.0f))
{
byte charset = font1.GdiCharSet;
}
备注
File 和 Font 是访问非托管资源(本例中为文件句柄和设备上下文)的托管类型的示例。 有许多其他类别的非托管资源和封装这些资源的类库类型。 所有此类类型都必须实现 IDisposable 接口。
通常,使用 IDisposable
对象时,应在 using
语句中声明和实例化此对象。 using
语句按照正确的方式调用对象上的 Dispose 方法,并(在按照前面所示方式使用它时)会导致在调用 Dispose 时对象自身处于范围之外。 在 using
块中,对象是只读的并且无法进行修改或重新分配。
using
语句确保调用 Dispose,即使在调用对象上的方法时出现异常也是如此。 通过将对象放入 try 块中,然后调用 finally 块中的 Dispose,可以实现相同的结果;实际上,这就是编译器转换 using
语句的方式。 前面的代码示例在编译时将扩展到以下代码(请注意,使用额外的大括号为对象创建有限范围):
{
Font font1 = new Font("Arial", 10.0f);
try
{
byte charset = font1.GdiCharSet;
}
finally
{
if (font1 != null)
((IDisposable)font1).Dispose();
}
}
可在 using
语句中声明一个类型的多个实例,如下面的示例中所示。
using (Font font3 = new Font("Arial", 10.0f),
font4 = new Font("Arial", 10.0f))
{
// Use font3 and font4.
}
可以实例化资源对象,然后将变量传递到 using
语句,但这不是最佳做法。 在这种情况下,该对象将在控制权离开 using
块之后保持在范围内,即使它可能将不再具有对其非托管资源的访问权限。 换句话说,再也无法完全初始化该对象。 如果尝试在 using
块外部使用该对象,则可能导致引发异常。 因此,通常最好在 using
语句中实例化该对象并将其范围限制在 using
块中。
Font font2 = new Font("Arial", 10.0f);
using (font2) // not recommended
{
// use font2
}
// font2 is still in scope
// but the method call throws an exception
float f = font2.GetHeight();
参考文献:
https://docs.microsoft.com/zh-cn/dotnet/csharp/language-reference/keywords/using
https://docs.microsoft.com/zh-cn/dotnet/csharp/index