[C#6] 1-using static

简介: 0. 目录 C#6 新增特性目录 1. 老版本的代码 1 using System; 2 3 namespace csharp6 4 { 5 internal class Program 6 { 7 private static ...

0. 目录

C#6 新增特性目录

1. 老版本的代码

 1 using System;
 2 
 3 namespace csharp6
 4 {
 5     internal class Program
 6     {
 7         private static void Main(string[] args)
 8         {
 9             Console.WriteLine("blackheart");
10         }
11     }
12 }

上面这段代码大家再熟悉不过了,使用静态类Console的静态方法WriteLine输出一行字符串。插播点关于CLR的相关知识,CLR在执行IL的期间时候是么有命名空间的概念的,它所知道的仅仅是成员的完全限定名(C#1 类型基础)。也就是在调用Console.WriteLine的时候,IL中使用的是完整的类型名称 System.Console.WriteLine 。打开ILDASM来看一看生成的IL代码,如下:

 1 .method private hidebysig static void  Main(string[] args) cil managed
 2 {
 3   .entrypoint
 4   // Code size       13 (0xd)
 5   .maxstack  8
 6   IL_0000:  nop
 7   IL_0001:  ldstr      "blackheart"
 8   IL_0006:  call       void [mscorlib]System.Console::WriteLine(string)
 9   IL_000b:  nop
10   IL_000c:  ret
11 } // end of method Program::Main

那么,在我们需要调用Console的很多方法的时候,就需要去写很多遍的Console前缀,能否简化一下呢?

2. C#6 using static新语法

 1 using static System.Console;
 2 
 3 namespace csharp6
 4 {
 5     internal class Program
 6     {
 7         private static void Main(string[] args)
 8         {
 9             WriteLine("blackheart");
10         }
11     }
12 }

重点部分在第一行 using static System.Console; ,我们使用“using static”引用了一个静态类型,System.Console,那么在当前这个全局作用域内,调用Console的任何静态成员,都可以省略掉Console.这个类型名前缀了。看起来是不是清爽多了!那么它的编译器做了什么奇妙的东西吗?我们用ILDASM看看IL,用IL来一探究竟:

 1 .method private hidebysig static void  Main(string[] args) cil managed
 2 {
 3   .entrypoint
 4   // Code size       13 (0xd)
 5   .maxstack  8
 6   IL_0000:  nop
 7   IL_0001:  ldstr      "blackheart"
 8   IL_0006:  call       void [mscorlib]System.Console::WriteLine(string)
 9   IL_000b:  nop
10   IL_000c:  ret
11 } // end of method Program::Main

和老的语法编译的结果一模一样的,,,so,它的本质只是个语法糖而已

2.1 可以using static非静态类型吗?

答案是可以的,但是只能使用它的静态方法,至于原因,不用解释了吧。

 1 using static csharp6.MyClass;
 2 
 3 namespace csharp6
 4 {
 5     public class MyClass
 6     {
 7         public void MyFunction(string value)
 8         {
 9         }
10 
11         public static void MyStaticFunction(string value)
12         {
13         }
14     }
15 
16     internal class Program
17     {
18         private static void Main(string[] args)
19         {
20             //不允许
21             MyFunction("blackheart");
22             //允许
23             MyStaticFunction("blackheart");
24         }
25     }
26 }

2.2 还有哪些类型可以使用using static?

除了class之外还支持structenum类型:

 1 using static csharp6.MyStruct;
 2 using static System.ConsoleColor;
 3 
 4 namespace csharp6
 5 {
 6     public struct MyStruct
 7     {
 8         public static void MyStructStaticFunction(string value)
 9         {
10         }
11     }
12 
13     internal class Program
14     {
15         private static void Main(string[] args)
16         {
17             //结构类型的静态函数
18             MyStructStaticFunction("blackheart");
19             //枚举ConsoleColor.Black
20             System.Console.ForegroundColor = Black;
21         }
22     }
23 }

2.3 using staitc成员签名与现有静态成员签名相同怎么处理?

现有静态成员优先级高,首选使用现有的静态成员。比如以下方法:

 1 using static System.Console;
 2 
 3 namespace csharp6
 4 {
 5     internal class Program
 6     {
 7         private static void Main(string[] args)
 8         {
 9             //签名相同的非using static导入的方法优先级高
10             //所以会调用我们自己声明的WriteLine,输出“我的优先级比较高!”
11             WriteLine("blackheart");
12         }
13 
14         //签名相同的WriteLine方法
15         private static void WriteLine(string value)
16         {
17             System.Console.WriteLine("我的优先级比较高!");
18         }
19     }
20 }

2.4 using static成员之间签名相同怎么处理?

先看下面这段代码:

 1 using static csharp6.MyClass;
 2 using static System.Console;
 3 
 4 namespace csharp6
 5 {
 6     public static class MyClass
 7     {
 8         public static void WriteLine(string value)
 9         {
10         }
11     }
12 
13     internal class Program
14     {
15         private static void Main(string[] args)
16         {
17             WriteLine("blackheart");
18             ReadKey();
19         }
20     }
21 }

我们using static了两个类型,这两个类型都有一个方法签名相同的WriteLine静态方法,编译器怎么处理呢?

编译器报错了,,,CS0121,告诉我们说在调用WriteLine的时候出现了歧义,它分不清楚我们要用哪个类型了。so,我们需要去掉一个using static或者使用老版本的写法

2.5 除了方法之外还能使用什么类型的成员?

静态属性,字段,事件等等,,,静态成员均可依靠using static 省略类型前缀。

 1 using static csharp6.MyClass;
 2 
 3 namespace csharp6
 4 {
 5     class MyClass
 6     {
 7         public static void Method() { }
 8         public static int Field;
 9         public static int Property { get; set; }
10         public static event System.Action Event;
11     }
12     internal class Program
13     {
14         private static void Main(string[] args)
15         {
16             Method();//静态方法
17             var field = Field;//静态字段
18             var property = Property;//静态属性
19             Event += Program_Event;//静态事件
20 
21         }
22 
23         private static void Program_Event()
24         {
25             throw new System.NotImplementedException();
26         }
27     }
28 }

3. using static 扩展方法

 既然using static可以应用在静态方法上,那么我们所熟知的在C#3中加入的扩展方法可以使用吗?答案是在特定的语法格式上可以扩展方法的第一个参数必须按照实例方法的调用方式书写才可以使用),笔者有点想不明白,扩展方法的实现是静态方法,只是第一个参数是一个特殊的this参数,为何直接用类型完全限定名可以用,而using static后缺不能使用呢?毕竟编译后都会翻译成完全限定名方式的调用。笔者实在想不明白。如下:

 1 using static System.Linq.Enumerable;
 2 
 3 namespace csharp6
 4 {
 5     internal class Program
 6     {
 7         private static void Main()
 8         {
 9             //允许,本来就是非扩展方法。
10             var range = Range(5, 17);
11             //不允许,想不明白的地方
12             //var odd = Where(range, i => i % 2 == 1); // 不允许
13             //按原理来解释,上面的代码最终会翻译成这样,实在想不明白为何上面的方法不被允许
14             var odd = System.Linq.Enumerable.Where(range, i => i % 2 == 1);
15             //允许,这个和odd上面一个odd的编译效果是完全一样的
16             var odd2 = range.Where(i => i % 2 == 1);
17         }
18     }
19 }

4. 总结

本篇博文介绍了C#6的一个新语法特性,using static语法导入一个类型,然后就可以在其全局作用域范围内(当前文件内)使用它可以访问(遵循访问修饰符的限定)类型的静态成员了,需要注意的几点是:

  1. 导入的成员签名和现有的成员签名相同时,使用现有的成员。
  2. 导入的成员之间出现成员签名相同的情况,使用的时候会编译不通过,需要一处一个using static才可,或者改为正常的调用方式。
  3. class,struct,emun类型可以使用using static导人。
  4. 扩展方法也可以使用using static,但是需要按照实例方法的调用方式来使用。

最后,也是最要紧的是,using static仅仅是编译器的语法糖,帮助我们简化代码的,和之前的写法并无任何本质上的差异,编译后是无任何差别的。

5. 参考

C# 语言参考-using指令:Using Static Type

 

作者: Blackheart
目录
相关文章
|
7月前
|
开发框架 .NET 编译器
C# 9.0中的静态匿名函数:引入static关键字的新用法
【1月更文挑战第15天】C# 9.0为匿名函数带来了一个新的修饰符static,允许开发者明确指定匿名函数不会捕获其包含作用域中的任何变量。这一特性增强了代码的性能和可读性,同时减少了因不小心捕获变量而导致的潜在错误。本文将详细探讨C# 9.0中静态匿名函数的语法、使用场景以及它们如何影响代码的性能和安全性。
|
7月前
|
存储 Java C++
31.C#:关键字static
31.C#:关键字static
68 1
|
移动开发 C#
C#中public与private与static
现在静下心来想要重新细致的过一遍C#,因为自己做C#没有底气,, 闲话少说 先来一句话 public(共有的) 声明的方法和属性,可以被外部调用. private(私有的) 声明的方法和属性,只能在本类中被调用,外部看不到.
995 0
|
C# 索引
C#中static静态变量的用法
原文:C#中static静态变量的用法 使用 static 修饰符声明属于类型本身而不是属于特定对象的静态成员static修饰符可用于类、字段、方法、属性、运算符、事件和构造函数,但不能用于索引器、析构函数或类以外的类型   静态全局变量 定义:在全局变量前,加上关键字 static 该变量就被定义成为了一个静态全局变量。
953 0
|
C# C++
c# static
c# static 类的静态成员 静态 成员变量/函数 用法同c++。 使用方法为 类名.成员。 静态构造函数 在 创建第一个实例 或 引用任何静态成员 之前,系统将自动调用静态构造函数。 可以用于静态类,也可用于非静态类。 静态构造函数既没有访问修饰符,也没有参数。 静态类 静态类只包含静态成员,不能被实例化。最大的特点是共享。 定义方法为: 类名前有 static关
824 0
|
C# 索引 编译器
C#基础知识系列七(base、this、new、override、abstract、virtual、static)
前言 本文主要来讲解一下C#中,自己觉得掌握的不怎么样或者用的不多,不太熟悉的关键字,主要包括base、this、new、override、abstract、virtual以及针对static字段和static构造函数之间的执行问题。
1291 0
C# Static
 static静态分配的,有两种情况:   A、 用在类里的属性、方法前面:   这样的静态属性与方法不需要创建实例就能访问,通过类名或对象名都能访问它,静态属性、方法只有“一份”:即如果一个类新建有N个对象,这N 个对象只有同一个静态属性与方法。  B、 方法内部的静态变量:    方法内部的静态变量,执行完静态变量值不消失,再次执行此对象的方法时,值仍存在,它不是在栈中分
747 0