C#中的using用法总结
using一般有两个作用:
1、作为语句,用于定义一个范围,在此范围的末尾将释放对象(IDisposable和IAsyncDisposable接口)
2、作为指令,用于引入命名空间或者类型,或者为引入的命名空间或者类型定义别名
using语句
using语句应该都很熟悉了吧,从最早的ADO.net,或者对文件、流的操作,一般都会使用using语句吧。
using(await using)语句的作用对象是实现了IDisposable(IAsyncDisposable)接口的对象,而实现IDisposable或者IAsyncDisposable接口的对象一般都是一些非托管对象,比如文件,我们在操作完非托管对象后,一般需要释放它们,而using(await using)就类似一个语法糖,它为IDisposable(IAsyncDisposable)接口的对象的提供了一个作用范围,在退出这个作用返回的时候,会自动调用Dispose(DisposeAsync)方法。
IAsyncDisposable是IDisposable的异步形式,一个简单的使用例子:
    public static async Task Main(string[] args)
    {
        //using针对IDisposable接口对象
        using (var reader = new StreamReader("text.log"))
        {
            var text = reader.ReadToEnd();
        }
        //await using针对IAsyncDisposable接口对象
        await using (var myUnmanagedObject = new MyUnmanagedObject())
        {
            var str = myUnmanagedObject.ToString();
        }
    }
    class MyUnmanagedObject : IAsyncDisposable
    {
        public async ValueTask DisposeAsync()
        {
            await Task.CompletedTask;
            Console.WriteLine("DisposeAsync");
        }
    }其实using(await using)的作用等价于下面的形式:
    public static async Task Main(string[] args)
    {
        //using针对IDisposable接口对象
        var reader = new StreamReader("text.log");
        try
        {
            var text = reader.ReadToEnd();
        }
        finally
        {
            reader.Dispose();
        }
        //await using针对IAsyncDisposable接口对象
        var myUnmanagedObject = new MyUnmanagedObject();
        try
        {
            var str = myUnmanagedObject.ToString();
        }
        finally
        {
            await myUnmanagedObject.DisposeAsync();
        }
    }也就是说,在using(await using)的范围内,无论有没有发生错误,都会自动调用Dispose(DisposeAsync)方法。
为了更方便的使用using(await using),我们还可以省略大括号,这意味着,using(await using)的作用区间就是从using(await using)开始至变量退出的区间,可以简单的理解为可以使用这个变量的范围区间,比如:
    public static async Task Main(string[] args)
    {
        //using针对IDisposable接口对象
        using var reader = new StreamReader("text.log");
        var text = reader.ReadToEnd();
        //await using针对IAsyncDisposable接口对象
        await using var myUnmanagedObject = new MyUnmanagedObject();
        var str = myUnmanagedObject.ToString();
        //退出方法前会自动调用Dispose或者DisposeAsync方法
        //也就是说using的范围是using开始至方法结尾
    }using指令
using指令常用于引入命名空间或者类,目前(C#10)一般有4种格式:
1、引入命名空间:using [命名空间]
比如:
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    namespace ClassLibrary
    {
        using System.IO;
        using System.Drawing;
        //其它代码
    }    using的位置
    1、源代码文件的开头,位于任何命名空间或类型声明之前。
    2、如果在任何命名空间中,则必须在该命名空间中的所有命名空间和类型之前2、与global结合(C#10提供):global using [命名空间]
比如:
    global using System;
    global using System.Collections.Generic;
    global using System.Linq;
    global using System.Text;
    global using System.Threading.Tasks;global using和using的区别是,using只是将命名空间作用于当前的源文件,而global using就是将命名空间作用于当前项目的所有源文件,这样就不需要我们每个文件都去引入了。
这是很好用的一个语法糖,我们可以在任何一个C#的源文件中使用global using,但是global using必须出现在文件开头,包括在那些没有global的using开头!
注:global using的作用,我们也可以通过修改csproj文件还完成:
    <ItemGroup>
        <Using Include="System"/>
        <Using Include="System.Collections.Generic"/>
        <Using Include="System.Linq"/>
        <Using Include="System.Text"/>
        <Using Include="System.Threading.Tasks"/>
    </ItemGroup>3、与static结合:using static [全限定名称的类型]
using static的作用就是将指定的类型的静态成员展开,这样我们在用的时候就不需要再写类型了,而是直接使用方法就可以了:
    using static System.Console;
    namespace ClassLibrary
    {
        class Program
        {
            void Main(string[] args)
            {
                WriteLine("Hello World!");
                //等价于
                Console.WriteLine("Hello World!");
            }
        }
    }使用using static时,需要注意几点:
    1、using static可以作用于任何类型,包括结构体、嵌套类型等,但是使用时必须使用全限定名称(命名空间+类型名成)
    2、当using static导致方法名称冲突时,需要使用通常的类型来指明,比如类中已经定义了一个WriteLine方法,那么就需要显示的用类型来指明
    3、using static只会导入自定义的静态成员,不会导入父类的静态成员此外,static也可以与global一起使用,表示往项目中的每个源文件都导入指定类型的静态成员,比如:
    global using static System.Console;
    namespace ClassLibrary
    {
        class Program
        {
            void Main(string[] args)
            {
                WriteLine("Hello World!");
                //现在你可以在当前项目的其它原文件中使用Console中的静态成员了
            }
        }
    }注:同样,我们可以通过修改csproj项目文件来实现global using static 的相关:
    <ItemGroup>
        <Using Include="System.Console" Static="true"/>
    </ItemGroup>4、定义别名:using [别名]=[命名空间|类型]
别名用于简化我们的代码,using定义的别名可以作用于命名空间,或者类型,比如:
    namespace ClassLibrary
    {
        using s = System;
        using c = System.Console;
        class Program
        {
            void Main(string[] args)
            {
                var now = s.DateTime.Now;
                c.WriteLine("Hello World!");
            }
        }
    }需要注意的是,这里的using,无论是对命名空间,还是类型,都必须使用全限定名称!
当然,using别名也可以与global结合,这里就不重复叙述了。
结语
说到using引入命名空间,不知道大家有没有考虑过这么一个问题,假如有两个dll,里面都有一个相同名称,相同命名空间的类型,如果我们同一个项目中引用这两个dll,我们怎么指定使用哪个类型?
例如:LibraryA项目有个类Library.MyClass,LibraryB项目有个类Library.MyClass,如果我们有一个LibraryC项目同时引用了LibraryA和LibraryB,那么在LibraryC中要使用LibraryA的Library.MyClass,如果直接引用Library.MyClass,那么肯定会报错,因为程序不知道到底是LibraryA还是LibraryB。这个时候,我们需要定义一个命名来区分。
在我们引用项目或者dll文件的依赖项中,右键依赖项=》属性,开发属性面板,有个别名的栏位,我们可以将LibraryA和LibraryB定义两个不一样的别名:
  

此外,我们也可以通过修改csproj项目文件来添加别名:
  <ItemGroup>
    <ProjectReference Include="..\LibraryA\LibraryA.csproj">
      <Aliases>A</Aliases>
    </ProjectReference>
    <ProjectReference Include="..\LibraryB\LibraryB.csproj">
      <Aliases>B</Aliases>
    </ProjectReference>
  </ItemGroup>接着在代码中使用extern alias声明一个外面的别名,就可以正常使用了:
    extern alias A;
    extern alias B;
    namespace ClassLibrary
    {
        class Program
        {
            void Main(string[] args)
            {
                var ClassA = new A::Library.MyClass();
                var ClassB = new B::Library.MyClass();
            }
        }
    }此时,using别名就提供了一个很好的作用:
    extern alias A;
    extern alias B;
    global using LibraryA = A::Library;
    global using LibraryB = B::Library;
    namespace ClassLibrary
    {
        class Program
        {
            void Main(string[] args)
            {
                var ClassA = new LibraryA.MyClass();
                var ClassB = new LibraryB.MyClass();
            }
        }
    }剩下的工作就交给LibraryA、LibraryB...
参考文档:
https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/statements/using
https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/using-directive

 
                
            
         浙公网安备 33010602011771号
浙公网安备 33010602011771号