fbpx
维基百科

C#

C#微软推出的一种基于.NET框架和后来的.NET的、面向对象的高级编程语言。C#是一种由C和C++衍生出来的面向对象的编程语言。它在继承C和C++强大功能的同时去掉了一些它们的复杂特性,使其成为C语言家族中的一种高效强大的编程语言。C#以.NET框架类库作为基础,拥有类似Visual Basic的快速开发能力。C#由安德斯·海尔斯伯格主持开发,微软在2000年发布了这种语言,希望借助这种语言来取代Java。C#已经成为Ecma国际国际标准组织的标准规范。

C#
编程范型结构化面向对象泛型
语言家族C
設計者微软
實作者微软
发行时间2000年,​22年前​(2000
目前版本
  • 11 (2022年11月8日;穩定版本)[1]
作業系統WindowsLinuxMac OS XAndroid
許可證
文件扩展名.cs, .csx
網站C#
主要實作產品
.NET.NET框架MonoDotGNU
衍生副語言
Spec#英语Spec SharpPolyphonic C#英语Polyphonic C sharp
啟發語言
C++JavaEiffelModula-3Object Pascal
影響語言
Clojure[4]D語言F#Java 5、NemerleVala

命名

C#的发音为“C sharp”,“#”读作“sharp”(/ʃɑːp/),命名启发于音乐上的音名“C♯”,在音乐中“C♯”表示C升半音,為比C高一点的音节,且“#”形似4个加号,微软借助这样的命名,以表示C#在一些语言特性方面对C++的提升的意思。

由於顯示器(標準字體瀏覽器等)的技術限制,且大部分的鍵盤配置上不存在升記號(♯),所以井號(#)被用於此程式語言的名稱中,約定在ECMA-334 C#語言規範中[6]

设计目标

ECMA标准列出的C#设计目标:

  • C#旨在设计成为一种「简单、现代、通用」,以及面向对象的程序设计语言
  • 此种语言的实现,应提供对于以下软件工程要素的支持:强类型檢查、数组维度检查、未初始化的变量引用检测、自动垃圾收集(Garbage Collection,指一种記憶體自動释放技术)。软件必须做到強大、持久,并具有较强的编程生产力。
  • 此种语言为在分布式环境中的开发提供适用的组件开发应用。
  • 为使程序员容易迁移到这种语言,源代码的可移植性十分重要,尤其是对于那些已熟悉C和C++的程序员而言。
  • 对国际化的支持非常重要。
  • C#适合为独立和嵌入式的系统编写程序,从使用复杂操作系统的大型系统到特定应用的小型系统均适用。
  • 虽然C#程序在存储和操作能力需求方面具备经济性,但此种语言在某些情況下并不能在性能和程式大小方面与C语言相抗衡。[來源請求]

歷史

Borland公司的首席研发设计师安德斯·海爾斯伯格(Anders Hejlsberg)在微軟開發了Visual J++ 1.0,很快的Visual J++由1.1版本升級到6.0版。SUN公司认为Visual J++ 违反了Java开发平台的中立性,对微软提出了诉讼。2000年6月26日微软在奥兰多举行的“职业开发人员技术大会”(PDC 2000)上,發表新的语言C#。C#语言取代了Visual J++,語言本身深受Visual Basic、Java、C和C++ 的影響。

版本

版本 語言規格 日期 .NET框架版本 Visual Studio的版本
ECMA ISO/IEC Microsoft
C# 1.0 2002年12月(页面存档备份,存于互联网档案馆 2003年4月(页面存档备份,存于互联网档案馆 2002年1月(页面存档备份,存于互联网档案馆 2002年1月 .NET Framework 1.0 Visual Studio .NET 2002
C# 1.1
C# 1.2
2003年10月(页面存档备份,存于互联网档案馆 2003年4月 .NET Framework 1.1英语.NET Framework 1.1 Visual Studio .NET 2003
C# 2.0 2006年9月(页面存档备份,存于互联网档案馆 2005年9月(页面存档备份,存于互联网档案馆 2005年11月 .NET Framework 2.0 Visual Studio 2005
C# 3.0 2007年8月(页面存档备份,存于互联网档案馆 2007年11月

.NET Framework 2.0 (Except LINQ)[7]
.NET Framework 3.0 (Except LINQ)[7]
.NET Framework 3.5

Visual Studio 2008
Visual Studio 2010
C# 4.0 2010年4月 2010年4月 .NET Framework 4 Visual Studio 2010
C# 5.0 2017年12月(页面存档备份,存于互联网档案馆 2018年12月(页面存档备份,存于互联网档案馆 2013年6月(页面存档备份,存于互联网档案馆 2012年8月 .NET Framework 4.5 Visual Studio 2012
Visual Studio 2013
C# 6.0 草案(页面存档备份,存于互联网档案馆 2015年7月/2016-06-27 .NET Framework 4.6/.NET Core 1.0 Visual Studio 2015
C# 7.0 建议草案 (页面存档备份,存于互联网档案馆 2017年3月 .NET Framework 4.6.2 Visual Studio 2017
C# 7.1 建议草案 (页面存档备份,存于互联网档案馆 2017年8月/2016-08-14 .NET Framework 4.7英语.NET Framework 4.7/.NET Core 2.0 Visual Studio 2017 version 15.3[8]
C# 7.2 建议草案 2017年11月 .NET Framework 4.7.1 Visual Studio 2017 version 15.5[9]
C# 7.3 建议草案 (页面存档备份,存于互联网档案馆 2018年5月/2018-05-30/2018-12-04 .NET Framework 4.7.2/.NET Core 2.1/.NET Core 2.2 Visual Studio 2017 version 15.7[9]
C# 8.0 建议草案 (页面存档备份,存于互联网档案馆 2019年9月/2019-09-23/2019-12-03 .NET Framework 4.8/.NET Core 3.0/.NET Core 3.1 Visual Studio 2019 version 16.3[9]
C# 9.0 建议草案 (页面存档备份,存于互联网档案馆 2020年9月 .NET 5 Visual Studio 2019 version 16.8[9]
C# 10.0[10] 建议草案 (页面存档备份,存于互联网档案馆 2021年11月
  • .NET 6.0
  • .NET 6.0.1
Visual Studio 2022 version 17.0[11]
C# 11.0[12] 建议草案 (页面存档备份,存于互联网档案馆 2022年8月
  • .NET 6.0
  • .NET 6.0.2
Visual Studio 2022 version 17.1[11]

語言特性

相對於CC++,這個語言在許多方面進行了限制和增強:

  • 指针(Pointer)只能用於不安全模式之中。大多數對象訪問透過安全的引用实现,以避免無效的調用,並且有許多算法用於验证溢出,指针只能用於調用值类型,以及受垃圾收集控制的托管對象。
  • 對象不能被顯式釋放,代替為當不存在被引用時透過垃圾回收器回收。
  • 只允許單一繼承(single inheritance),但是一個類可以實現多個接口(interfaces)。
  • C#比C++更加類型安全。默认的安全轉換是隱含轉換,例如由短整型轉換為長整型和從衍生類轉換為基本類。而接口布尔型同整型,及枚舉型同整型不允許隱含轉換,非空指针(透過引用相似對象)同用戶定義類型的隱含轉換字段被顯式的確定,不同於C++的複製構造函數。
  • 数组声明語法不同("int[] a = new int[5]"而不是"int a[5]")。
  • 枚舉位於其所在的命名空間中。
  • C#中沒有模版(Template),但是在C# 2.0中引入了泛型(Generic programming),並且支持一些C++模版不支持的特性。比如泛型參數中的類型約束。另一方面,表達式不能像C++模版中被用於類型參數。
  • 屬性支持,使用類似訪問成員的方式調用。
  • 完整的反射支持。

C# 2.0的特性

针对于.NET SDK 2.0(相对应于ECMA-334标准第三版),C# 的新特性有:

部分类

分部類別将類別的实现分在多个文件中。该概念于C# 中首次出现,除了能将一个類別的成员分开存放,还使ASP.NET中的代码后置得以实现。代码后置实现了HTML代码和后台交互代码的分离。

file1.cs:

public partial class MyClass1 {  public void MyMethod1()  {  // implementation  } } 

file2.cs:

public partial class MyClass1 {  public void MyMethod2()  {  // implementation  } } 

分部類別这个特性允许将一个類別的编写工作分配给多个人,一人写一个文件,便于版本控制。它又可以隔离自动生成的代码和人工书写的代码,例如设计窗体应用程序时。

泛型

泛型,或参数化类型,是被C#支持的.NET 2.0特性。不同于C++模版,.NET参数化类型是在运行时被实例化,而不是编译时,因此它可以跨语言,而C++模版却不行。C#泛型类在编译时,先生成中间代码IL,通用类型符号T只是一个占位符;在实例化类时,根据实际数据类型代替T并由即时编译器(JIT)生成本地代码,其中使用了实际的数据类型,等同于用实际类型写的普通的类。

它支持的一些特性并不被C++模版直接支持,比如约束泛型参数实现一个接口。另一方面,C# 不支持无类型的泛型参数。不像Java中的泛型,在CLI虚拟机中,.NET generics使用具化生成泛型参数,它允许优化和保存类型信息。[13]

泛型类中,可以用where关键字对参数类型实现约束。例如:

class Node<T, V>  where T : Stack, IComparable, new(), class  where V : Stack, struct {...} 

上述表示T和V必须是Stack类或其派生类,T必须继承了IComparable接口、有无参构造函数、是引用类型;V必须是值类型。

泛型不仅能作用在类上,也可单独用在类的方法上,称为“泛型方法”。

泛型类的静态成员变量在相同封闭类间共享,不同的封闭类间不共享。

泛型类中的方法重载,参数类型T和V在运行时确定,不影响这个类通过编译。C#的泛型是在实例的方法被调用时检查重载是否产生混淆,而不是在泛型类本身编译时检查。特别地,当一般方法与泛型方法具有相同的签名时,会覆盖泛型方法。

静态類別

静态類別它不能被实例化,并且只能有静态成员。这同很多过程语言中的模块概念相类似。

迭代器

一种新形式的迭代器它提供了函数式编程中的generator,使用yield return

类似于Python中使用的yield

// Method that takes an iterable input (possibly an array) // and returns all even numbers. public static IEnumerable<int> GetEven(IEnumerable<int> numbers) {  foreach (int i in numbers)  {  if (i % 2 == 0) yield return i;  } } 

注意事项:

  • foreach循环时考虑线程安全性,不要试图对被遍历的集合进行remove和add等操作
  • IEnumerable接口是LINQ特性的核心接口。只有实现了IEnumerable接口的集合,才能执行相关的LINQ操作,比如select,where等

匿名方法

匿名方法类似于函数式编程中的闭包[14]匿名方法是通过使用 delegate 关键字创建委托实例来声明的。例如:

delegate void NumberChanger(int n);   NumberChanger nc = delegate(int x) {  Console.WriteLine("Anonymous Method: {0}", x); }; public void Foo(object parameter) {  // ...  ThreadPool.QueueUserWorkItem(delegate  {  // anonymous delegates have full access to local variables of the enclosing method  if(parameter == ...)  {   // ...   }  // ...  }); } 

委托的协变和逆变

委托签名的协变和逆变,[15]

属性访问器可以被单独设置访问级别

例子:

string status = string.Empty; public string Status {  get { return status; } // anyone can get value of this property,  protected set { status = value; } // but only derived classes can change it } 

可空类型

可空类型(跟个问号,如int? i = null;)允许设置null给任何类类型。

int? i = null; object o = i; if(o == null)  Console.WriteLine("Correct behaviour - runtime version from September 2005 or later"); else  Console.WriteLine("Incorrect behaviour - pre-release runtime (from before September 2005)"); 

??運算子

??):如果左运算数表达式的值不为空值时回傳该值,如果为空值则返回右运算数表达式的值。

object nullObj = null;  object obj = new Object();  return nullObj ?? obj; // returns obj 

主要用作将一个可空类型赋值给不可空类型的简便语法

int? i = null; int j = i ?? 0; // Unless i is null, initialize j to i. Else (if i is null), initialize j to 0. 

C# 3.0的特性

C# 3.0发布于2007年10月17日,是.NET Framework 3.5的一部分,它的新特性灵感来自于函数式编程语言,如:HaskellML,并广泛地引入了Language Integrated Query(LINQ)模式到通用語言運行庫中e.[16]

Linq

语言集成查询(英語:Language Integrated Query,缩写:LINQ):[17] 上下文相关关键字"from, where, select"可用于查询SQL、XML、集合等。这些标识符在LINQ上下文中被作为关键字,但是它们的增加不会破坏原有的名为fromwhereselect的变量。

类型初始化器

Customer c = new Customer(); c.Name = "James"; 

可写作:

Customer c = new Customer() { Name = "James" }; 

集合初始化器

MyList list = new MyList(); list.Add(1); list.Add(2); 

可写作

MyList list = new MyList { 1, 2 }; 

假设MyList实现了System.Collections.IEnumerable且有一个Add方法method[18]

匿名類型

var x = new { Name = "James" }; 

局部变量类型推断

局部变量类型推断

var x = new Dictionary<string, List<float>>(); 

等同于

Dictionary<string, List<float>> x = new Dictionary<string, List<float>>(); 

它只是一个语法糖,这个特性被匿名类型声明时所需要

Lambda表达式

Lambda表达式(無函式名稱的物件方法在程式語言中的表達語法):

listOfFoo.Where(  delegate(Foo x)  {  return x.Size > 10;   } ) 
可写作
listOfFoo.Where(x => x.Size > 10); 

编译器翻译Lambda表达式为强类型委托或强类型表达式树。

注意事项:

  • 如果只有一个参数,可以省略括号(),例如 item=>{Console.WriteLine("只有一个参数{0}的Lambda表达式",item); };
  • 如果只有一个返回值的语句,可以省略花括号{}、return关键字、分号,例如 item => {return item % 2 == 0;};改写成:item =>item %2 == 0;
  • Lambda表达式可以分配给Func,Action或Predicate委托。

自动化属性

编译器将自动生成私有变量和适当的getter(get访问器)和setter(set访问器),如:

public string Name {  get;   set;  } 

扩展方法

扩展方法能够使现有的类型添加方法,而无需创建心的派生类型、重新编译或以其它方式修改原始类型。

使用拓展方法,必须在一个非嵌套、非泛型的静态类中定义一个静态方法,方法第一个参数必须附加this关键字作为前缀,第一个参数不能有其它修饰符(如ref或者out),这个方法将被编译器添加到该this的类型中。

public static class IntExtensions {  public static void PrintPlusOne(this int x)   {  Console.WriteLine(x + 1);  } }   int foo = 0; foo.PrintPlusOne(); 

注意事项:

  • 扩展方法只会增加编译器的工作,但不会影响程序运行性能(用继承的方式为一个类型增加特性反而会影响性能)
  • 如果原来的类中有一个方法,跟扩展方法一样,那么扩展方法不会被调用,编译器也不会提示

分部方法

允许代码生成器生成方法声明作为扩展点,如果有人在另一个部分类实现了它才会被包含于原代码编译。[19]

  1. 分部方法(Partial methods)必须定义在分部类(partial classes)中
  2. 定义分部方法需要用partial做修饰符
  3. 分部方法不一定总是有执行内容的,也就是说定义的方法可以一句操作语句都没有
  4. 分部方法返回值必须是void
  5. 分部方法可以是静态(static)方法
  6. 分部方法可以包含参数,参数可以包含以下修饰词:this,ref,params
  7. 分部方法必须是私有(private)方法

例子:

partial class C {  static partial void M(int i); // defining declaration } partial class C {  static partial void M(int i)  {  dosomething();  } } 

C# 4.0的特性

dynamic类型

C# 4.0新增dynamic关键字,提供動態編程(dynamic programming),把既有的靜態物件標記為動態物件,類似javascript, PythonRuby

dynamic关键字标记的实例被处理成一个特殊包装的object对象,取消了CLI的编译时类型检查,编译时被假定支持任何操作,但如果并不实际支持则运行时报错。

dynamic calc = GetCalculator(); int sum = calc.Add(10, 20); 

具名參數與可選參數

public StreamReader OpenFile(string path, int bufferSize = 1024) { ... } 

呼叫OpenFile時,順序可以完全顛倒:

OpenFile(bufferSize: 4096, path: "foo.txt"); 

與COM组件互動

在C#中打開一個Word文件:

static void Main(string[] args) {  Word.Application wordApplication = new Word.Application() { Visible = true };  wordApplication.Documents.Open(@"C:\plant.docx", ReadOnly: true); } 

在C#中指定Excel的某一格文字:

excelObj.Cells[5, 5].Value = "This is sample text"; 

泛型的协变和逆变

C# 4.0支援协变和逆变,例如在泛型介面可以加上in、out修饰字。

public interface IComparer<in T>  {   int Compare(T left, T right);  } public interface IEnumerable<out T> : IEnumerable {  IEnumerator<T> GetEnumerator(); } 

C# 5.0的特性

  1. C# Evolution Matrix
  2. Async Feature (补充: async和await是一对语法糖,允许开发人员非常轻松的调用基于TASK的异步编程)async-await关键字并不会真的创建一个线程池任务,完成这个动作依赖于被调用方法中的函数。这一点在许多C#的中文教程中被忽略,导致许多学习的新手误以为await关键字会直接创建一个新的线程池任务。
  3. Caller Information

C# 6.0的特性

  1. 唯讀 Auto 屬性
  2. Auto 屬性初始設定式
  3. 使用靜態
  4. Null - 條件運算子
  5. 字串插值
  6. 例外狀況篩選條件
  7. nameof 運算式
  8. Catch 和 Finally 區塊中的 Await
  9. 索引初始設定式
  10. 集合初始設定式的擴充方法
  11. 改進的多載解析

表达式主体(Expression-bodied)用于类的方法和只读属性

using System; public class Person {  public Person(string firstName, string lastName)  {  fname = firstName;  lname = lastName;  }  private string fname;  private string lname;  public override string ToString() => $"{fname} {lname}".Trim(); //返回值类型string  public void DisplayName() => Console.WriteLine(ToString()); //返回值类型void  public string Name => $"{fname} {lname}".Trim();//只读属性 } 

C# 7.0的特性

out 變數

能夠直接宣告一個變數在它要傳入的地方,當成一個 out 的引數[20]

弃元

元组/对象的解构:

var tuple = (1, 2, 3, 4, 5); (_, _, _, _, var fifth) = tuple; 

使用 is/switch 的模式匹配:

var obj = CultureInfo.CurrentCulture.DateTimeFormat; switch (obj) { case IFormatProvider fmt:  Console.WriteLine($"{fmt} object");  break; case null:  Console.Write("A null object reference");  break; case object _:  Console.WriteLine("Some object type without format information");  break; } if (obj is object _) { ... } 

对具有 out 参数的方法的调用:

var point = new Point(10, 10); // 只要 x, 不关心 y point.GetCoordinates(out int x, out _); 

作用域内独立使用场景:

void Test(Dto dto) {  _ = dto ?? throw new ArgumentNullException(nameof(dto)); } 

表达式主体(Expression-bodied)用于类的属性、构造器、终结器、索引器

using System; public class Location {  private string locationName;  public Location(string name) => Name = name; //构造函数  public string Name  {  get => locationName; //get属性  set => locationName = value; //set属性  }  public override string ToString() => GetType().Name;  ~Location() => Console.WriteLine($"The {ToString()} finalizer is executing."); //析构函数  private string[] types = { "Baseball", "Basketball", "Football",  "Hockey", "Soccer", "Tennis",  "Volleyball" };  public string this[int i]   {  get => types[i]; //索引器  set => types[i] = value;  } } 

C# 7.1的特性

  1. async``Main方法
  2. default常值運算式
  3. 推斷的 tuple 項目名稱

C# 7.2的特性

  1. 具備實值型別的參考語意
  2. 無後置具名引數
  3. 數值常值中的前置底線
  4. private protected 存取修飾詞

C# 8.0的特性

  1. 可空引用类型
  2. await yield return可异步返回的迭代器
  3. Index 索引类型和Range区间类型
  4. 允许在声明接口时为接口成员提供默认实现
  5. 递归的模式匹配
  6. 表达式形式的Switch关键字
  7. 在编译器可做类型推断的情况下,允许进一步省略类型声明

C# 9.0的特性

新的「Record」類型

记录类型, 是一种引用类型, 默认是不可变的。 记录类型的相等判断可以通过引用或者结构进行判断的。

  • 优点:记录类型是轻量级的不可变类型,可以减少大量的代码, 可以按照结构和引用进行比较;
  • 缺点:需要实例化大量的对象;
// 默认不可变的记录类型 public record Person(string Name, int Age);  // 可变记录类型 public record MutablePerson(string Name, int Age) {  public string Name { get; set; } = Name;  public int Age { get; set; } = Age; }   var person1 = new Person("Alice", 40); var person2 = new Person("Alice", 40);   Console.WriteLine(person1 == person2); // True 结构相同 Console.WriteLine(person1.Equals(person2)); // True 结构相同 Console.WriteLine(ReferenceEquals(person1, person2)); // False, 引用不同   // 改变默认的记录! --> 创建一个新的记录。 var person3 = person1 with { Age = 43 }; Console.WriteLine(person3 == person1); // False 结构不同   // 解构 (Destruct) 一个记录, 将记录的属性提取为本地变量 var (name, age) = person3;   var person4 = new MutablePerson("Alice", 40); person4.Age = 43;   // 记录类型也可以被继承 public record Citizen(string Name, int Age, string Country) : Person(Name, Age); var citizen = new Citizen("Alice", 40, "China"); Console.WriteLine(person1 == citizen); // False 类型不同; 

「init」存取子

init存取子表示該屬性所屬類型僅能在建構函式(Constructor)中或是屬性初始化式子中賦予其值,如果嘗試在其他地方設定該屬性的值,在編譯時便會遭編譯器阻止。

範例如下:在這個範例中,建立了一個Student類型,並且屬性StudentNameStudentID只能在初始化時賦予其值。

public class Student {  public Student()  {  }    public Student(string studentName,string studentID)  {  StudentName = studentName;  StudentID = studentID;  }    public string StudentName { get; init; } = "Default Name";  public string StudentID { get; init; } = "00000000"; } 

如果在此時撰寫以下程式碼:

Student DemoStudent = new Student(); DemoStudent.StudentName = "Test Name"; 

編譯器便會無法編譯並且擲回錯誤。

而如果要建立學生名稱為「Test Name」,學生ID為「0001」的學生,則需要寫成:

Student DemoStudent = new Student() //物件初始化運算式 {  StudentName = "Test Name";  StudentID = "0001" }; 

或是

Student DemoStudent = new Student("Test Name","0001"); //藉由類型的建構式初始化StudentName以及StudentID。 

最上層陳述式或称顶级语句

在以前的版本,開發者在撰寫最上層陳述式(如Program.cs)程式碼時,需要包含完整的namespace與class架構,因此如果要撰寫Hello World程式時,程式碼就會是:

using System; namespace ConsoleApp1 {  class Program  {  static void Main(string[] args)  {  Console.WriteLine("Hello World!");  }  } } 

但是在C# 9.0之後,最上層陳述式的程式碼不需要包含namespace以及class,可將其簡化為:

using System; Console.WriteLine("Hello World!"); //或者简化为一行语句: System.Console.WriteLine("Hello World!"); 

注意, 一个程序中, 只能有一个文件使用顶级语句, 并且顶级语句必须位于命名空间或类型定义之前。

lambda弃元参数

Func<int, int, int> zero = (_, _) => 0; Func<int, int, int> func = delegate (int _, int _) { return 0; }; 

在 C# 9 之前,即便不使用的 Lambda 参数也需要给它命名。C# 9 支持弃元参数一方面简化了命名,另一方面也节省了内存分配。更重要的是它使得编程的意图更明确,让人一看就知道这个参数是不用的,增强了代码的可读性和可维护性。

只能初始化的设置器

Init only setters,只能通过对象初始化进行赋值的属性。

public class InitDemo {  public string Start { get; init; }  public string Stop { get; init; } }   // initDemo.Start = "Now"; // Error // initDemo.End = "Tomorrow"; // Error   var initDemo = new InitDemo {  Start = "Now",  Stop = "Tomorrow" }; 

函数指针

使用 delegate* 可以声明函数指针。

unsafe class FunctionPointer {  static int GetLength(string s) => s.Length;  delegate*<string, int> functionPointer = &GetLength; }   public void Test() {  Console.WriteLine(functionPointer("test")); // 4; } 

跳过本地初始化

[System.Runtime.CompilerServices.SkipLocalsInit] static unsafe void DemoLocalsInit() {  int x;  // 注意, x 没有初始化, 输出结果不确定;  Console.WriteLine(*&x); } 

原生整数类型

两个新的整数类型 nint 和 nunit , 依赖宿主机以及编译设定。

协变返回类型

协变返回类型为重写方法的返回类型提供了灵活性。覆盖方法可以返回从被覆盖的基础方法的返回类型派生的类型。

class Person {  public virtual Person GetPerson() { return new Person(); } } class Student : Person {  public override Student GetPerson() { return new Student(); } } 

模块初始化代码

ModuleInitializerAttribute 为组件 (assembly) 定义初始化代码, 当初始化/加载时执行, 可以类比类的静态构造函数, 但是是组件级别的。

  • 必须是静态的、无参数的、无返回值的方法;
  • 不能是范型方法,也不能包含在范型类中;
  • 不能是私有函数,必须是公开 (public) 或者内部 (internal) 的函数;

静态 lambda 表达式

static 修饰符添加到 lambda 表达式或匿名方法 。这将无法捕获局部变量或实例状态,从而防止意外捕获其他变量。

分部方法扩展

移除了分部方法的下述限制:

  • 必须具有 void 返回类型。
  • 不能具有 out 参数。
  • 不能具有任何可访问性(隐式 private )。

初始化表达式的简化

如果创建对象的类型已知时,可以在new表达式中省略该类型。

Point p = new(1, 1); Dictionary<string, int> dict = new();   Point[] points = { new(1, 1), new (2, 2), new (3, 3) }; var list = new List<Point> { new(1, 1), new(2, 2), new(3, 3)}; 

在本地函数上添加标记

using System.Diagnostics; using System.Diagnostics.CodeAnalysis; namespace CoreApp2 {   class Program  {  static void Main(string[] args)  {  [Conditional("DEBUG")]  static void DoSomething([NotNull] string test)  {  System.Console.WriteLine("Do it!");  }  DoSomething("Doing!");  }  } } 

GetEnumerator 扩展

可以为任意类型添加一个 GetEnumerator 扩展方法, 返回一个 IEnumerator 或者 IAsyncEnumerator 实例, 从而在 foreach 循环中使用。

using System.Collections.Generic; using System.Collections.ObjectModel; namespace CoreApp2 {  public static class Extensions  {  public static IEnumerator<T> GetEnumerator<T>(this IEnumerator<T> enumerator) => enumerator;  }  class Program  {  static void Main(string[] args)  {  IEnumerator<string> enumerator = new Collection<string> {"A", "B", "C"}.GetEnumerator();  foreach (var item in enumerator)  {  Console.WriteLine(item);  }  }  } } 

模式匹配增强

Type patterns 类型匹配,判断一个变量的类型

object obj = new int(); var type = obj switch {  string => "string",  int => "int",  _ => "obj" }; Console.WriteLine(type); // int 

Relational patterns 关系匹配:

class Person {   public string name;   public int age;   public Person(string a, int b) { name = a;age = b; }  public void Deconstruct(out string a,out int b){a = name;b = age; } } class Program {   static void Main(string[] args)  {  var person1 = new Person("Alice", 40);  var inRange = person1 switch  {  (_, < 18) => "less than 18",  (_, > 18) => "greater than 18",  (_, 18) => "18 years old!"  };  Console.WriteLine(inRange); // greater than 18  } } 

Conjunctive and patterns 逻辑合取匹配:

// And pattern var person1 = new Person("Alice", 40); var ageInRange = person1 switch {  (_, < 18) => "less than 18",  ("Zhang Zhimin", _) and (_, >= 18) => "Alice is greater than 18" }; Console.WriteLine(ageInRange); // Alice is greater than 18 

Disjunctive or patterns 逻辑析取匹配:

// Or pattern var person1 = new Person("Alice", 40); var ageInRange = person1 switch {  (_, < 18) => "less than 18",  (_, 18) or (_, > 18) => "18 or greater" }; Console.WriteLine(ageInRange); // 18 or greater 

Negated not patterns 逻辑非匹配

// Not pattern var person1 = new Person("Alice", 40); var meOrNot = person1 switch {  not ("Alice", 40) => "Not me!",  _ => "Me :-)" }; Console.WriteLine(meOrNot); // Me :-) 

Parenthesized patterns 带括号的优先级匹配:

// Parenthesized patterns var is10 = new IsNumber(true, 10); var n10 = is10 switch {  ((_, > 1 and < 5) and (_, > 5 and < 9)) or (_, 10) => "10",  _ => "not 10" }; Console.WriteLine(n10); // 10 

C# 10.0的特性

record struct

解决了 record 只能给 class 而不能给 struct 用的问题:

record struct Point(int X, int Y); 

sealed record ToString 方法

可以把 record 里的 ToString 方法标记成 sealed

struct 无参构造函数

无参构造函数使得new struct() 和 default(struct) 的语义不一样

用with创建新的匿名类型对象

var x = new { A = 1, B = 2 }; var y = x with { A = 3 }; 

这里 y.A 将会是 3 。

全局的 using

可以给整个项目启用 using,不需要每个文件都写一份。

文件范围的 namespace

以前写 namespace 还得带一层大括号。现在如果一个文件里只有一个 namespace 的话,直接在文件开头写:namespace MyNamespace;

常量字符串插值

const string x = "hello"; const string y = $"{x}, world!"; 

lambda的改进

lambda 可以带 attributes

f = [Foo] (x) => x; // 给 lambda 设置 f = [return: Foo] (x) => x; // 给 lambda 返回值设置 f = ([Foo] x) => x; // 给 lambda 参数设置 

指定返回值类型

此前 C# 的 lambda 返回值类型靠推导,C# 10允许在参数列表之前显式指定 lambda 返回值类型:

f = int () => 4; 

支持 ref 、in 、out 等修饰

f = ref int (ref int x) => ref x; // 返回一个参数的引用 

头等函数

函数可以隐式转换到 delegate,于是函数上升为头等函数(first function):

void Foo() { Console.WriteLine("hello"); } var x = Foo; x(); // hello 

自然委托类型

lambda 可自动创建自然委托类型,于是不再需要写出类型:

var f = () => 1; // Func<int> var g = string (int x, string y) => $"{y}{x}"; // Func<int, string, string> var h = "test".GetHashCode; // Func<int> 

CallerArgumentExpression

使用CallerArgumentExpression这个attribute,编译器会自动填充调用参数的表达式字符串,例如:

void Foo(int value, [CallerArgumentExpression("value")] string? expression = null) {  Console.WriteLine(expression + " = " + value); } 

当你调用 Foo(4 + 5) 时,会输出 4 + 5 = 9。这对测试框架极其有用

tuple 的混合定义和使用

int y = 0; (var x, y, var z) = (1, 2, 3); 

于是 y 就变成 2 了,同时还创建了两个变量 x 和 z,分别是 1 和 3 。

接口支持抽象静态方法

.NET 6中这个特性为preview特性。

泛型 attribute

在方法上指定 AsyncMethodBuilder

在方法上用 [AsyncMethodBuilder(...)],来使用自己实现的 async method builder,代替自带的 Task 或者 ValueTask 的异步方法构造器。有助于实现零开销的异步方法。

line 指示器支持行列和范围

以前 #line 只能用来指定一个文件中的某一行,现在可以指定行列和范围:

#line (startLine, startChar) - (endLine, endChar) charOffset "fileName" // 比如 #line (1, 1) - (2, 2) 3 "test.cs" 

嵌套属性模式匹配改进

以前在匹配嵌套属性的时候需要这么写:

if (a is { X: { Y: { Z: 4 } } }) { ... } 

现在只需要简单的:

if (a is { X.Y.Z: 4 }) { ... } 

改进的字符串插值

实现接近零开销的字符串插值。

Source Generator v2

包括强类型的代码构建器,以及增量编译的支持等

程序的执行

C#通常不被编译成为能够直接在计算机上执行的二进制本地代码。与Java类似,它被编译成为中间代码(Microsoft Intermediate Language),然后通过.NET Framework虚拟机——被称为通用语言运行库——执行。

所有的.Net编程语言都被编译成这种被称为通用中间语言的中间代码。因此虽然最终的程序在表面上仍然与传统意义上的可执行文件都具有“.exe”的后缀名。如果计算机上没有安装.Net Framework,那么这些程序会弹出对话框,要求用户下载.net framework。

在程序执行时,.Net Framework将中间代码翻译成为二进制机器码,从而使它得到正确的运行。最终的二进制代码被存储在一个缓冲区(Buffer)中。所以一旦程序使用了相同的代码,那么将会调用缓冲区中的版本。这样如果一个.Net程序第二次被运行,那么这种翻译不需要进行第二次,速度明显加快。

标准化

微软公司已经向ECMA申请将C#作为一种标准。在2001年12月,ECMA发布了ECMA-334 C#语言规范。C#在2003年成为一个ISO标准(ISO/IEC 23270)。现在有一些独立的实现正在进行,包括:

示例

C# 的Hello World程式

下面是一個在命令列上輸出Hello World的小程序,這種程序通常作為開始學習程序語言的第一個步驟:

using System; namespace ConsoleApp1 {  class Program  {  static void Main(string[] args)  {  Console.WriteLine("Hello World!");  }  } } 

实现

微软正在引领开源参考 C# 编译器和工具集的开发。 第一个编译器 Roslyn编译成中间语言(IL),第二个编译器 RyuJIT,[21] 是一个 JIT(即时)编译器,它是动态的,进行动态优化并编译将 IL 转换为 CPU 前端的本机代码。[22] RyuJIT 是开源的,用 C++ 编写。[23] Roslyn 完全是用 托管代码 (C#)编写的,已经开放并且功能以 API 的形式出现。因此,它使开发人员能够创建重构和诊断工具。[2][24] 官方实现的两个分支是 .NET Framework(闭源,仅限 Windows)和 .NET Core(开源,跨平台);它们最终融合为一个开源实现:.NET 5.0。[25] 在 .NET Framework 4.6 中,新的 JIT 编译器取代了前者。[21][26]

其他 C# 编译器(其中一些包括公共语言基础结构和 .NET 类库的实现):

  • 微軟的Rotor项目(Rotor Project,目前稱為Shared Source Common Language Infrastructure英语Shared Source Common Language Infrastructure),提供了通用语言运行库Common Language Runtime)的實作與C# 編譯器。但是Shared Source Common Language Infrastructure在2006年的2.0版後就停止了。
  • 由Microsoft贊助的Mono 项目提供了C# 編譯器,它提供了一个开源 C# 编译器、一个完整的 CLI 开源实现,同時也接近百分之百地實作了.NET Framework类库。而Mono後來衍伸出由微軟認可的第三方套件Xamarin
  • Dot GNU 專案(现已停产)也提供了另一個自由版本的C# 編譯器,也提供了.NET Framework类库的實作。

游戏引擎 Unity 使用C# 作为其主要脚本语言。由于Microsoft 捐赠了 24,000 美元, Godot 游戏引擎实现了一个可选的 C# 模块。

参考文献

  1. ^ Welcome to C# 11. [2022年12月10日]. 
  2. ^ 2.0 2.1 The Roslyn .NET compiler provides C# and Visual Basic languages with rich code analysis APIs.: dotnet/roslyn. November 13, 2019 [2021-08-16]. (原始内容于2021-02-22) –通过GitHub. 
  3. ^ CoreCLR is the runtime for .NET Core. It includes the garbage collector, JIT compiler, primitive data types and low-level classes.: dotnet/coreclr. November 13, 2019 [2021-08-16]. (原始内容于2019-10-14) –通过GitHub. 
  4. ^ . [2017-01-11]. 原始内容存档于2017-01-11. 
  5. ^ What's new in C# 10. [2022-02-16]. (原始内容于2022-02-08). 
  6. ^ (PDF) 4th. Ecma International. June 2006 [2012-01-26]. (原始内容 (PDF)存档于2012-12-02). 
  7. ^ 7.0 7.1 . Danielmoth.com. 2007-05-13 [2012年10月4日]. (原始内容存档于2012-09-29). 
  8. ^ 存档副本. [2018-09-06]. (原始内容于2018-01-22). 
  9. ^ 9.0 9.1 9.2 9.3 存档副本. [2018-09-06]. (原始内容于2018-01-22). 
  10. ^ What's new in C# 10. docs.microsoft.com. [2021-11-10]. (原始内容于2022-02-08) (美国英语). 
  11. ^ 11.0 11.1 Visual Studio 2022 version 17.0 Release Notes. docs.microsoft.com. [2022-06-24]. (原始内容于2022-08-06). 
  12. ^ What's new in C# 10. docs.microsoft.com. [2021-11-10]. (原始内容于2022-02-08) (美国英语). 
  13. ^ An Introduction to C# Generics. [2020-09-25]. (原始内容于2019-09-24). 
  14. ^ Anonymous Methods (C#). [2008-10-24]. (原始内容于2008-04-17). 
  15. ^ Covariance and Contravariance in Delegates (C#). [2008-10-24]. (原始内容于2008-10-12). 
  16. ^ Tim Anderson. C# pulling ahead of Java - Lead architect paints rosy C# picture. Reg Developer. The Register. 2006-11-14 [2007-01-20]. (原始内容于2007-01-21). 
  17. ^ . Microsoft MSDN. 2007 [2007-08-13]. (原始内容存档于2007-01-16) (英语). 
  18. ^ The Mellow Musings of Dr. T : What is a collection?. [2008-10-24]. (原始内容于2008-12-18). 
  19. ^ Partial Methods. [2007-10-06]. (原始内容于2007-10-16). 
  20. ^ 一覽 C# 7.0 中的新功能. [2016-09-14]. (原始内容于2018-10-02). 
  21. ^ 21.0 21.1 The RyuJIT transition is complete!. microsoft.com. June 19, 2018 [July 20, 2021]. (原始内容于July 19, 2019). 
  22. ^ Managed Execution Process. microsoft.com. [July 20, 2021]. (原始内容于December 23, 2017). 
  23. ^ coreclr/src/jit/. github.com. [July 20, 2021]. (原始内容于January 9, 2019). 
  24. ^ C# Guide. docs.microsoft.com. [2017-11-20]. (原始内容于2022-08-13). 
  25. ^ 5.0.8. microsoft.com. [July 20, 2021]. (原始内容于April 23, 2020). 
  26. ^ Mitigation: New 64-bit JIT Compiler. microsoft.com. [July 20, 2021]. (原始内容于April 5, 2018). 

外部連結

此條目介紹的是微软開發的程序设计语言, 关于音樂上的音名, 请见, 音名, 是微软推出的一种基于, net框架和后来的, net的, 面向对象的高级编程语言, 是一种由c和c, 衍生出来的面向对象的编程语言, 它在继承c和c, 强大功能的同时去掉了一些它们的复杂特性, 使其成为c语言家族中的一种高效强大的编程语言, net框架类库作为基础, 拥有类似visual, basic的快速开发能力, 由安德斯, 海尔斯伯格主持开发, 微软在2000年发布了这种语言, 希望借助这种语言来取代java, 已经成为ecma国际和. 此條目介紹的是微软開發的程序设计语言 关于音樂上的音名 请见 C 音名 C 是微软推出的一种基于 NET框架和后来的 NET的 面向对象的高级编程语言 C 是一种由C和C 衍生出来的面向对象的编程语言 它在继承C和C 强大功能的同时去掉了一些它们的复杂特性 使其成为C语言家族中的一种高效强大的编程语言 C 以 NET框架类库作为基础 拥有类似Visual Basic的快速开发能力 C 由安德斯 海尔斯伯格主持开发 微软在2000年发布了这种语言 希望借助这种语言来取代Java C 已经成为Ecma国际和国际标准组织的标准规范 C 编程范型结构化 面向对象 泛型语言家族C設計者微软實作者微软发行时间2000年 22年前 2000 目前版本11 2022年11月8日 穩定版本 1 作業系統Windows Linux Mac OS X Android許可證Roslyn compiler MIT License 2 NET Core MIT License 3 文件扩展名 cs csx網站C 主要實作產品 NET NET框架 Mono DotGNU衍生副語言Cw Spec 英语 Spec Sharp Polyphonic C 英语 Polyphonic C sharp 啟發語言C Java Eiffel Modula 3 Object Pascal影響語言Clojure 4 D語言 F Java 5 Nemerle Vala 目录 1 命名 2 设计目标 3 歷史 3 1 版本 4 語言特性 5 C 2 0的特性 5 1 部分类 5 2 泛型 5 3 静态類別 5 4 迭代器 5 5 匿名方法 5 6 委托的协变和逆变 5 7 属性访问器可以被单独设置访问级别 5 8 可空类型 5 9 運算子 6 C 3 0的特性 6 1 Linq 6 2 类型初始化器 6 3 集合初始化器 6 4 匿名類型 6 5 局部变量类型推断 6 6 Lambda表达式 6 7 自动化属性 6 8 扩展方法 6 9 分部方法 7 C 4 0的特性 7 1 dynamic类型 7 2 具名參數與可選參數 7 3 與COM组件互動 7 4 泛型的协变和逆变 8 C 5 0的特性 9 C 6 0的特性 9 1 表达式主体 Expression bodied 用于类的方法和只读属性 10 C 7 0的特性 10 1 out 變數 10 2 弃元 10 3 表达式主体 Expression bodied 用于类的属性 构造器 终结器 索引器 11 C 7 1的特性 12 C 7 2的特性 13 C 8 0的特性 14 C 9 0的特性 14 1 新的 Record 類型 14 2 init 存取子 14 3 最上層陳述式或称顶级语句 14 4 lambda弃元参数 14 5 只能初始化的设置器 14 6 函数指针 14 7 跳过本地初始化 14 8 原生整数类型 14 9 协变返回类型 14 10 模块初始化代码 14 11 静态 lambda 表达式 14 12 分部方法扩展 14 13 初始化表达式的简化 14 14 在本地函数上添加标记 14 15 GetEnumerator 扩展 14 16 模式匹配增强 15 C 10 0的特性 15 1 record struct 15 2 sealed record ToString 方法 15 3 struct 无参构造函数 15 4 用with创建新的匿名类型对象 15 5 全局的 using 15 6 文件范围的 namespace 15 7 常量字符串插值 15 8 lambda的改进 15 8 1 lambda 可以带 attributes 15 8 2 指定返回值类型 15 8 3 支持 ref in out 等修饰 15 8 4 头等函数 15 8 5 自然委托类型 15 8 6 CallerArgumentExpression 15 9 tuple 的混合定义和使用 15 10 接口支持抽象静态方法 15 11 泛型 attribute 15 12 在方法上指定 AsyncMethodBuilder 15 13 line 指示器支持行列和范围 15 14 嵌套属性模式匹配改进 15 15 改进的字符串插值 15 16 Source Generator v2 16 程序的执行 17 标准化 18 示例 18 1 C 的Hello World程式 19 实现 20 参考文献 21 外部連結命名 编辑C 的发音为 C sharp 读作 sharp ʃ ɑː p 命名启发于音乐上的音名 C 在音乐中 C 表示C升半音 為比C高一点的音节 且 形似4个加号 微软借助这样的命名 以表示C 在一些语言特性方面对C 的提升的意思 由於顯示器 標準字體 瀏覽器等 的技術限制 且大部分的鍵盤配置上不存在升記號 所以井號 被用於此程式語言的名稱中 約定在ECMA 334 C 語言規範中 6 设计目标 编辑ECMA标准列出的C 设计目标 C 旨在设计成为一种 简单 现代 通用 以及面向对象的程序设计语言 此种语言的实现 应提供对于以下软件工程要素的支持 强类型檢查 数组维度检查 未初始化的变量引用检测 自动垃圾收集 Garbage Collection 指一种記憶體自動释放技术 软件必须做到強大 持久 并具有较强的编程生产力 此种语言为在分布式环境中的开发提供适用的组件开发应用 为使程序员容易迁移到这种语言 源代码的可移植性十分重要 尤其是对于那些已熟悉C和C 的程序员而言 对国际化的支持非常重要 C 适合为独立和嵌入式的系统编写程序 从使用复杂操作系统的大型系统到特定应用的小型系统均适用 虽然C 程序在存储和操作能力需求方面具备经济性 但此种语言在某些情況下并不能在性能和程式大小方面与C语言相抗衡 來源請求 歷史 编辑原Borland公司的首席研发设计师安德斯 海爾斯伯格 Anders Hejlsberg 在微軟開發了Visual J 1 0 很快的Visual J 由1 1版本升級到6 0版 SUN公司认为Visual J 违反了Java开发平台的中立性 对微软提出了诉讼 2000年6月26日微软在奥兰多举行的 职业开发人员技术大会 PDC 2000 上 發表新的语言C C 语言取代了Visual J 語言本身深受Visual Basic Java C和C 的影響 版本 编辑 版本 語言規格 日期 NET框架版本 Visual Studio的版本ECMA ISO IEC MicrosoftC 1 0 2002年12月 页面存档备份 存于互联网档案馆 2003年4月 页面存档备份 存于互联网档案馆 2002年1月 页面存档备份 存于互联网档案馆 2002年1月 NET Framework 1 0 Visual Studio NET 2002C 1 1C 1 2 2003年10月 页面存档备份 存于互联网档案馆 2003年4月 NET Framework 1 1 英语 NET Framework 1 1 Visual Studio NET 2003C 2 0 2006年6月 2006年9月 页面存档备份 存于互联网档案馆 2005年9月 页面存档备份 存于互联网档案馆 2005年11月 NET Framework 2 0 Visual Studio 2005C 3 0 否 2007年8月 页面存档备份 存于互联网档案馆 2007年11月 NET Framework 2 0 Except LINQ 7 NET Framework 3 0 Except LINQ 7 NET Framework 3 5 Visual Studio 2008Visual Studio 2010C 4 0 2010年4月 2010年4月 NET Framework 4 Visual Studio 2010C 5 0 2017年12月 页面存档备份 存于互联网档案馆 2018年12月 页面存档备份 存于互联网档案馆 2013年6月 页面存档备份 存于互联网档案馆 2012年8月 NET Framework 4 5 Visual Studio 2012Visual Studio 2013C 6 0 否 草案 页面存档备份 存于互联网档案馆 2015年7月 2016 06 27 NET Framework 4 6 NET Core 1 0 Visual Studio 2015C 7 0 建议草案 页面存档备份 存于互联网档案馆 2017年3月 NET Framework 4 6 2 Visual Studio 2017C 7 1 否 否 建议草案 页面存档备份 存于互联网档案馆 2017年8月 2016 08 14 NET Framework 4 7 英语 NET Framework 4 7 NET Core 2 0 Visual Studio 2017 version 15 3 8 C 7 2 否 否 建议草案 2017年11月 NET Framework 4 7 1 Visual Studio 2017 version 15 5 9 C 7 3 否 否 建议草案 页面存档备份 存于互联网档案馆 2018年5月 2018 05 30 2018 12 04 NET Framework 4 7 2 NET Core 2 1 NET Core 2 2 Visual Studio 2017 version 15 7 9 C 8 0 否 否 建议草案 页面存档备份 存于互联网档案馆 2019年9月 2019 09 23 2019 12 03 NET Framework 4 8 NET Core 3 0 NET Core 3 1 Visual Studio 2019 version 16 3 9 C 9 0 否 否 建议草案 页面存档备份 存于互联网档案馆 2020年9月 NET 5 Visual Studio 2019 version 16 8 9 C 10 0 10 否 否 建议草案 页面存档备份 存于互联网档案馆 2021年11月 NET 6 0 NET 6 0 1 Visual Studio 2022 version 17 0 11 C 11 0 12 否 否 建议草案 页面存档备份 存于互联网档案馆 2022年8月 NET 6 0 NET 6 0 2 Visual Studio 2022 version 17 1 11 語言特性 编辑相對於C和C 這個語言在許多方面進行了限制和增強 指针 Pointer 只能用於不安全模式之中 大多數對象訪問透過安全的引用实现 以避免無效的調用 並且有許多算法用於验证溢出 指针只能用於調用值类型 以及受垃圾收集控制的托管對象 對象不能被顯式釋放 代替為當不存在被引用時透過垃圾回收器回收 只允許單一繼承 single inheritance 但是一個類可以實現多個接口 interfaces C 比C 更加類型安全 默认的安全轉換是隱含轉換 例如由短整型轉換為長整型和從衍生類轉換為基本類 而接口布尔型同整型 及枚舉型同整型不允許隱含轉換 非空指针 透過引用相似對象 同用戶定義類型的隱含轉換字段被顯式的確定 不同於C 的複製構造函數 数组声明語法不同 int a new int 5 而不是 int a 5 枚舉位於其所在的命名空間中 C 中沒有模版 Template 但是在C 2 0中引入了泛型 Generic programming 並且支持一些C 模版不支持的特性 比如泛型參數中的類型約束 另一方面 表達式不能像C 模版中被用於類型參數 屬性支持 使用類似訪問成員的方式調用 完整的反射支持 C 2 0的特性 编辑针对于 NET SDK 2 0 相对应于ECMA 334标准第三版 C 的新特性有 部分类 编辑 分部類別将類別的实现分在多个文件中 该概念于C 中首次出现 除了能将一个類別的成员分开存放 还使ASP NET中的代码后置得以实现 代码后置实现了HTML代码和后台交互代码的分离 file1 cs public partial class MyClass1 public void MyMethod1 implementation file2 cs public partial class MyClass1 public void MyMethod2 implementation 分部類別这个特性允许将一个類別的编写工作分配给多个人 一人写一个文件 便于版本控制 它又可以隔离自动生成的代码和人工书写的代码 例如设计窗体应用程序时 泛型 编辑 泛型 或参数化类型 是被C 支持的 NET 2 0特性 不同于C 模版 NET参数化类型是在运行时被实例化 而不是编译时 因此它可以跨语言 而C 模版却不行 C 泛型类在编译时 先生成中间代码IL 通用类型符号T只是一个占位符 在实例化类时 根据实际数据类型代替T并由即时编译器 JIT 生成本地代码 其中使用了实际的数据类型 等同于用实际类型写的普通的类 它支持的一些特性并不被C 模版直接支持 比如约束泛型参数实现一个接口 另一方面 C 不支持无类型的泛型参数 不像Java中的泛型 在CLI虚拟机中 NET generics使用具化生成泛型参数 它允许优化和保存类型信息 13 泛型类中 可以用where关键字对参数类型实现约束 例如 class Node lt T V gt where T Stack IComparable new class where V Stack struct 上述表示T和V必须是Stack类或其派生类 T必须继承了IComparable接口 有无参构造函数 是引用类型 V必须是值类型 泛型不仅能作用在类上 也可单独用在类的方法上 称为 泛型方法 泛型类的静态成员变量在相同封闭类间共享 不同的封闭类间不共享 泛型类中的方法重载 参数类型T和V在运行时确定 不影响这个类通过编译 C 的泛型是在实例的方法被调用时检查重载是否产生混淆 而不是在泛型类本身编译时检查 特别地 当一般方法与泛型方法具有相同的签名时 会覆盖泛型方法 静态類別 编辑 静态類別它不能被实例化 并且只能有静态成员 这同很多过程语言中的模块概念相类似 迭代器 编辑 一种新形式的迭代器它提供了函数式编程中的generator 使用yield return类似于Python中使用的yield Method that takes an iterable input possibly an array and returns all even numbers public static IEnumerable lt int gt GetEven IEnumerable lt int gt numbers foreach int i in numbers if i 2 0 yield return i 注意事项 foreach循环时考虑线程安全性 不要试图对被遍历的集合进行remove和add等操作 IEnumerable接口是LINQ特性的核心接口 只有实现了IEnumerable接口的集合 才能执行相关的LINQ操作 比如select where等匿名方法 编辑 匿名方法类似于函数式编程中的闭包 14 匿名方法是通过使用 delegate 关键字创建委托实例来声明的 例如 delegate void NumberChanger int n NumberChanger nc delegate int x Console WriteLine Anonymous Method 0 x public void Foo object parameter ThreadPool QueueUserWorkItem delegate anonymous delegates have full access to local variables of the enclosing method if parameter 委托的协变和逆变 编辑 委托签名的协变和逆变 15 属性访问器可以被单独设置访问级别 编辑 例子 string status string Empty public string Status get return status anyone can get value of this property protected set status value but only derived classes can change it 可空类型 编辑 可空类型 跟个问号 如int i null 允许设置null给任何类类型 int i null object o i if o null Console WriteLine Correct behaviour runtime version from September 2005 or later else Console WriteLine Incorrect behaviour pre release runtime from before September 2005 運算子 编辑 如果左运算数表达式的值不为空值时回傳该值 如果为空值则返回右运算数表达式的值 object nullObj null object obj new Object return nullObj obj returns obj 主要用作将一个可空类型赋值给不可空类型的简便语法 int i null int j i 0 Unless i is null initialize j to i Else if i is null initialize j to 0 C 3 0的特性 编辑C 3 0发布于2007年10月17日 是 NET Framework 3 5的一部分 它的新特性灵感来自于函数式编程语言 如 Haskell和ML 并广泛地引入了Language Integrated Query LINQ 模式到通用語言運行庫中e 16 Linq 编辑 语言集成查询 英語 Language Integrated Query 缩写 LINQ 17 上下文相关关键字 from where select 可用于查询SQL XML 集合等 这些标识符在LINQ上下文中被作为关键字 但是它们的增加不会破坏原有的名为from where或select的变量 类型初始化器 编辑 Customer c new Customer c Name James 可写作 Customer c new Customer Name James 集合初始化器 编辑 MyList list new MyList list Add 1 list Add 2 可写作 MyList list new MyList 1 2 假设MyList实现了System Collections IEnumerable且有一个Add方法method 18 匿名類型 编辑 var x new Name James 局部变量类型推断 编辑局部变量类型推断 var x new Dictionary lt string List lt float gt gt 等同于 Dictionary lt string List lt float gt gt x new Dictionary lt string List lt float gt gt 它只是一个语法糖 这个特性被匿名类型声明时所需要 Lambda表达式 编辑 Lambda表达式 無函式名稱的物件方法在程式語言中的表達語法 listOfFoo Where delegate Foo x return x Size gt 10 可写作listOfFoo Where x gt x Size gt 10 编译器翻译Lambda表达式为强类型委托或强类型表达式树 注意事项 如果只有一个参数 可以省略括号 例如 item gt Console WriteLine 只有一个参数 0 的Lambda表达式 item 如果只有一个返回值的语句 可以省略花括号 return关键字 分号 例如 item gt return item 2 0 改写成 item gt item 2 0 Lambda表达式可以分配给Func Action或Predicate委托 自动化属性 编辑 编译器将自动生成私有变量和适当的getter get访问器 和setter set访问器 如 public string Name get set 扩展方法 编辑 扩展方法能够使现有的类型添加方法 而无需创建心的派生类型 重新编译或以其它方式修改原始类型 使用拓展方法 必须在一个非嵌套 非泛型的静态类中定义一个静态方法 方法第一个参数必须附加this关键字作为前缀 第一个参数不能有其它修饰符 如ref或者out 这个方法将被编译器添加到该this的类型中 public static class IntExtensions public static void PrintPlusOne this int x Console WriteLine x 1 int foo 0 foo PrintPlusOne 注意事项 扩展方法只会增加编译器的工作 但不会影响程序运行性能 用继承的方式为一个类型增加特性反而会影响性能 如果原来的类中有一个方法 跟扩展方法一样 那么扩展方法不会被调用 编译器也不会提示分部方法 编辑 允许代码生成器生成方法声明作为扩展点 如果有人在另一个部分类实现了它才会被包含于原代码编译 19 分部方法 Partial methods 必须定义在分部类 partial classes 中 定义分部方法需要用partial做修饰符 分部方法不一定总是有执行内容的 也就是说定义的方法可以一句操作语句都没有 分部方法返回值必须是void 分部方法可以是静态 static 方法 分部方法可以包含参数 参数可以包含以下修饰词 this ref params 分部方法必须是私有 private 方法例子 partial class C static partial void M int i defining declaration partial class C static partial void M int i dosomething C 4 0的特性 编辑dynamic类型 编辑 C 4 0新增dynamic关键字 提供動態編程 dynamic programming 把既有的靜態物件標記為動態物件 類似javascript Python或Ruby dynamic关键字标记的实例被处理成一个特殊包装的object对象 取消了CLI的编译时类型检查 编译时被假定支持任何操作 但如果并不实际支持则运行时报错 dynamic calc GetCalculator int sum calc Add 10 20 具名參數與可選參數 编辑 public StreamReader OpenFile string path int bufferSize 1024 呼叫OpenFile時 順序可以完全顛倒 OpenFile bufferSize 4096 path foo txt 與COM组件互動 编辑 在C 中打開一個Word文件 static void Main string args Word Application wordApplication new Word Application Visible true wordApplication Documents Open C plant docx ReadOnly true 在C 中指定Excel的某一格文字 excelObj Cells 5 5 Value This is sample text 泛型的协变和逆变 编辑 C 4 0支援协变和逆变 例如在泛型介面可以加上in out修饰字 public interface IComparer lt in T gt int Compare T left T right public interface IEnumerable lt out T gt IEnumerable IEnumerator lt T gt GetEnumerator C 5 0的特性 编辑C Evolution Matrix Async Feature 补充 async和await是一对语法糖 允许开发人员非常轻松的调用基于TASK的异步编程 async await关键字并不会真的创建一个线程池任务 完成这个动作依赖于被调用方法中的函数 这一点在许多C 的中文教程中被忽略 导致许多学习的新手误以为await关键字会直接创建一个新的线程池任务 Caller InformationC 6 0的特性 编辑唯讀 Auto 屬性 Auto 屬性初始設定式 使用靜態 Null 條件運算子 字串插值 例外狀況篩選條件 nameof 運算式 Catch 和 Finally 區塊中的 Await 索引初始設定式 集合初始設定式的擴充方法 改進的多載解析表达式主体 Expression bodied 用于类的方法和只读属性 编辑 using System public class Person public Person string firstName string lastName fname firstName lname lastName private string fname private string lname public override string ToString gt fname lname Trim 返回值类型string public void DisplayName gt Console WriteLine ToString 返回值类型void public string Name gt fname lname Trim 只读属性 C 7 0的特性 编辑out 變數 编辑 能夠直接宣告一個變數在它要傳入的地方 當成一個 out 的引數 20 弃元 编辑元组 对象的解构 var tuple 1 2 3 4 5 var fifth tuple 使用 is switch 的模式匹配 var obj CultureInfo CurrentCulture DateTimeFormat switch obj case IFormatProvider fmt Console WriteLine fmt object break case null Console Write A null object reference break case object Console WriteLine Some object type without format information break if obj is object 对具有 out 参数的方法的调用 var point new Point 10 10 只要 x 不关心 y point GetCoordinates out int x out 作用域内独立使用场景 void Test Dto dto dto throw new ArgumentNullException nameof dto 表达式主体 Expression bodied 用于类的属性 构造器 终结器 索引器 编辑 using System public class Location private string locationName public Location string name gt Name name 构造函数 public string Name get gt locationName get属性 set gt locationName value set属性 public override string ToString gt GetType Name Location gt Console WriteLine The ToString finalizer is executing 析构函数 private string types Baseball Basketball Football Hockey Soccer Tennis Volleyball public string this int i get gt types i 索引器 set gt types i value C 7 1的特性 编辑async Main方法 default常值運算式 推斷的 tuple 項目名稱C 7 2的特性 编辑具備實值型別的參考語意 無後置具名引數 數值常值中的前置底線 private protected 存取修飾詞C 8 0的特性 编辑可空引用类型 await yield return可异步返回的迭代器 Index 索引类型和Range区间类型 允许在声明接口时为接口成员提供默认实现 递归的模式匹配 表达式形式的Switch关键字 在编译器可做类型推断的情况下 允许进一步省略类型声明C 9 0的特性 编辑新的 Record 類型 编辑 记录类型 是一种引用类型 默认是不可变的 记录类型的相等判断可以通过引用或者结构进行判断的 优点 记录类型是轻量级的不可变类型 可以减少大量的代码 可以按照结构和引用进行比较 缺点 需要实例化大量的对象 默认不可变的记录类型 public record Person string Name int Age 可变记录类型 public record MutablePerson string Name int Age public string Name get set Name public int Age get set Age var person1 new Person Alice 40 var person2 new Person Alice 40 Console WriteLine person1 person2 True 结构相同 Console WriteLine person1 Equals person2 True 结构相同 Console WriteLine ReferenceEquals person1 person2 False 引用不同 改变默认的记录 gt 创建一个新的记录 var person3 person1 with Age 43 Console WriteLine person3 person1 False 结构不同 解构 Destruct 一个记录 将记录的属性提取为本地变量 var name age person3 var person4 new MutablePerson Alice 40 person4 Age 43 记录类型也可以被继承 public record Citizen string Name int Age string Country Person Name Age var citizen new Citizen Alice 40 China Console WriteLine person1 citizen False 类型不同 init 存取子 编辑 init存取子表示該屬性所屬類型僅能在建構函式 Constructor 中或是屬性初始化式子中賦予其值 如果嘗試在其他地方設定該屬性的值 在編譯時便會遭編譯器阻止 範例如下 在這個範例中 建立了一個Student類型 並且屬性StudentName與StudentID只能在初始化時賦予其值 public class Student public Student public Student string studentName string studentID StudentName studentName StudentID studentID public string StudentName get init Default Name public string StudentID get init 00000000 如果在此時撰寫以下程式碼 Student DemoStudent new Student DemoStudent StudentName Test Name 編譯器便會無法編譯並且擲回錯誤 而如果要建立學生名稱為 Test Name 學生ID為 0001 的學生 則需要寫成 Student DemoStudent new Student 物件初始化運算式 StudentName Test Name StudentID 0001 或是 Student DemoStudent new Student Test Name 0001 藉由類型的建構式初始化StudentName以及StudentID 最上層陳述式或称顶级语句 编辑 在以前的版本 開發者在撰寫最上層陳述式 如Program cs 程式碼時 需要包含完整的namespace與class架構 因此如果要撰寫Hello World程式時 程式碼就會是 using System namespace ConsoleApp1 class Program static void Main string args Console WriteLine Hello World 但是在C 9 0之後 最上層陳述式的程式碼不需要包含namespace以及class 可將其簡化為 using System Console WriteLine Hello World 或者简化为一行语句 System Console WriteLine Hello World 注意 一个程序中 只能有一个文件使用顶级语句 并且顶级语句必须位于命名空间或类型定义之前 lambda弃元参数 编辑 Func lt int int int gt zero gt 0 Func lt int int int gt func delegate int int return 0 在 C 9 之前 即便不使用的 Lambda 参数也需要给它命名 C 9 支持弃元参数一方面简化了命名 另一方面也节省了内存分配 更重要的是它使得编程的意图更明确 让人一看就知道这个参数是不用的 增强了代码的可读性和可维护性 只能初始化的设置器 编辑 Init only setters 只能通过对象初始化进行赋值的属性 public class InitDemo public string Start get init public string Stop get init initDemo Start Now Error initDemo End Tomorrow Error var initDemo new InitDemo Start Now Stop Tomorrow 函数指针 编辑 使用 delegate 可以声明函数指针 unsafe class FunctionPointer static int GetLength string s gt s Length delegate lt string int gt functionPointer amp GetLength public void Test Console WriteLine functionPointer test 4 跳过本地初始化 编辑 System Runtime CompilerServices SkipLocalsInit static unsafe void DemoLocalsInit int x 注意 x 没有初始化 输出结果不确定 Console WriteLine amp x 原生整数类型 编辑 两个新的整数类型 nint 和 nunit 依赖宿主机以及编译设定 协变返回类型 编辑协变返回类型为重写方法的返回类型提供了灵活性 覆盖方法可以返回从被覆盖的基础方法的返回类型派生的类型 class Person public virtual Person GetPerson return new Person class Student Person public override Student GetPerson return new Student 模块初始化代码 编辑 ModuleInitializerAttribute 为组件 assembly 定义初始化代码 当初始化 加载时执行 可以类比类的静态构造函数 但是是组件级别的 必须是静态的 无参数的 无返回值的方法 不能是范型方法 也不能包含在范型类中 不能是私有函数 必须是公开 public 或者内部 internal 的函数 静态 lambda 表达式 编辑 static 修饰符添加到 lambda 表达式或匿名方法 这将无法捕获局部变量或实例状态 从而防止意外捕获其他变量 分部方法扩展 编辑 移除了分部方法的下述限制 必须具有 void 返回类型 不能具有 out 参数 不能具有任何可访问性 隐式 private 初始化表达式的简化 编辑 如果创建对象的类型已知时 可以在new表达式中省略该类型 Point p new 1 1 Dictionary lt string int gt dict new Point points new 1 1 new 2 2 new 3 3 var list new List lt Point gt new 1 1 new 2 2 new 3 3 在本地函数上添加标记 编辑 using System Diagnostics using System Diagnostics CodeAnalysis namespace CoreApp2 class Program static void Main string args Conditional DEBUG static void DoSomething NotNull string test System Console WriteLine Do it DoSomething Doing GetEnumerator 扩展 编辑 可以为任意类型添加一个 GetEnumerator 扩展方法 返回一个 IEnumerator 或者 IAsyncEnumerator 实例 从而在 foreach 循环中使用 using System Collections Generic using System Collections ObjectModel namespace CoreApp2 public static class Extensions public static IEnumerator lt T gt GetEnumerator lt T gt this IEnumerator lt T gt enumerator gt enumerator class Program static void Main string args IEnumerator lt string gt enumerator new Collection lt string gt A B C GetEnumerator foreach var item in enumerator Console WriteLine item 模式匹配增强 编辑 Type patterns 类型匹配 判断一个变量的类型 object obj new int var type obj switch string gt string int gt int gt obj Console WriteLine type int Relational patterns 关系匹配 class Person public string name public int age public Person string a int b name a age b public void Deconstruct out string a out int b a name b age class Program static void Main string args var person1 new Person Alice 40 var inRange person1 switch lt 18 gt less than 18 gt 18 gt greater than 18 18 gt 18 years old Console WriteLine inRange greater than 18 Conjunctive and patterns 逻辑合取匹配 And pattern var person1 new Person Alice 40 var ageInRange person1 switch lt 18 gt less than 18 Zhang Zhimin and gt 18 gt Alice is greater than 18 Console WriteLine ageInRange Alice is greater than 18 Disjunctive or patterns 逻辑析取匹配 Or pattern var person1 new Person Alice 40 var ageInRange person1 switch lt 18 gt less than 18 18 or gt 18 gt 18 or greater Console WriteLine ageInRange 18 or greater Negated not patterns 逻辑非匹配 Not pattern var person1 new Person Alice 40 var meOrNot person1 switch not Alice 40 gt Not me gt Me Console WriteLine meOrNot Me Parenthesized patterns 带括号的优先级匹配 Parenthesized patterns var is10 new IsNumber true 10 var n10 is10 switch gt 1 and lt 5 and gt 5 and lt 9 or 10 gt 10 gt not 10 Console WriteLine n10 10C 10 0的特性 编辑record struct 编辑解决了 record 只能给 class 而不能给 struct 用的问题 record struct Point int X int Y sealed record ToString 方法 编辑 可以把 record 里的 ToString 方法标记成 sealed struct 无参构造函数 编辑 无参构造函数使得new struct 和 default struct 的语义不一样 用with创建新的匿名类型对象 编辑 var x new A 1 B 2 var y x with A 3 这里 y A 将会是 3 全局的 using 编辑 可以给整个项目启用 using 不需要每个文件都写一份 文件范围的 namespace 编辑 以前写 namespace 还得带一层大括号 现在如果一个文件里只有一个 namespace 的话 直接在文件开头写 namespace MyNamespace 常量字符串插值 编辑 const string x hello const string y x world lambda的改进 编辑 lambda 可以带 attributes 编辑 f Foo x gt x 给 lambda 设置 f return Foo x gt x 给 lambda 返回值设置 f Foo x gt x 给 lambda 参数设置 指定返回值类型 编辑 此前 C 的 lambda 返回值类型靠推导 C 10允许在参数列表之前显式指定 lambda 返回值类型 f int gt 4 支持 ref in out 等修饰 编辑 f ref int ref int x gt ref x 返回一个参数的引用 头等函数 编辑函数可以隐式转换到 delegate 于是函数上升为头等函数 first function void Foo Console WriteLine hello var x Foo x hello 自然委托类型 编辑lambda 可自动创建自然委托类型 于是不再需要写出类型 var f gt 1 Func lt int gt var g string int x string y gt y x Func lt int string string gt var h test GetHashCode Func lt int gt CallerArgumentExpression 编辑使用CallerArgumentExpression这个attribute 编译器会自动填充调用参数的表达式字符串 例如 void Foo int value CallerArgumentExpression value string expression null Console WriteLine expression value 当你调用 Foo 4 5 时 会输出 4 5 9 这对测试框架极其有用tuple 的混合定义和使用 编辑 int y 0 var x y var z 1 2 3 于是 y 就变成 2 了 同时还创建了两个变量 x 和 z 分别是 1 和 3 接口支持抽象静态方法 编辑 NET 6中这个特性为preview特性 泛型 attribute 编辑 在方法上指定 AsyncMethodBuilder 编辑 在方法上用 AsyncMethodBuilder 来使用自己实现的 async method builder 代替自带的 Task 或者 ValueTask 的异步方法构造器 有助于实现零开销的异步方法 line 指示器支持行列和范围 编辑以前 line 只能用来指定一个文件中的某一行 现在可以指定行列和范围 line startLine startChar endLine endChar charOffset fileName 比如 line 1 1 2 2 3 test cs 嵌套属性模式匹配改进 编辑 以前在匹配嵌套属性的时候需要这么写 if a is X Y Z 4 现在只需要简单的 if a is X Y Z 4 改进的字符串插值 编辑 实现接近零开销的字符串插值 Source Generator v2 编辑 包括强类型的代码构建器 以及增量编译的支持等程序的执行 编辑C 通常不被编译成为能够直接在计算机上执行的二进制本地代码 与Java类似 它被编译成为中间代码 Microsoft Intermediate Language 然后通过 NET Framework的虚拟机 被称为通用语言运行库 执行 所有的 Net编程语言都被编译成这种被称为通用中间语言的中间代码 因此虽然最终的程序在表面上仍然与传统意义上的可执行文件都具有 exe 的后缀名 如果计算机上没有安装 Net Framework 那么这些程序会弹出对话框 要求用户下载 net framework 在程序执行时 Net Framework将中间代码翻译成为二进制机器码 从而使它得到正确的运行 最终的二进制代码被存储在一个缓冲区 Buffer 中 所以一旦程序使用了相同的代码 那么将会调用缓冲区中的版本 这样如果一个 Net程序第二次被运行 那么这种翻译不需要进行第二次 速度明显加快 标准化 编辑微软公司已经向ECMA申请将C 作为一种标准 在2001年12月 ECMA发布了ECMA 334 C 语言规范 C 在2003年成为一个ISO标准 ISO IEC 23270 现在有一些独立的实现正在进行 包括 自由软件基金会的dotGNU Portable NET 页面存档备份 存于互联网档案馆 Mono 页面存档备份 存于互联网档案馆 Baltie C IDE for children and young Baltie 页面存档备份 存于互联网档案馆 示例 编辑C 的Hello World程式 编辑 下面是一個在命令列上輸出Hello World的小程序 這種程序通常作為開始學習程序語言的第一個步驟 using System namespace ConsoleApp1 class Program static void Main string args Console WriteLine Hello World 实现 编辑微软正在引领开源参考 C 编译器和工具集的开发 第一个编译器 Roslyn编译成中间语言 IL 第二个编译器 RyuJIT 21 是一个 JIT 即时 编译器 它是动态的 进行动态优化并编译将 IL 转换为 CPU 前端的本机代码 22 RyuJIT 是开源的 用 C 编写 23 Roslyn 完全是用 托管代码 C 编写的 已经开放并且功能以 API 的形式出现 因此 它使开发人员能够创建重构和诊断工具 2 24 官方实现的两个分支是 NET Framework 闭源 仅限 Windows 和 NET Core 开源 跨平台 它们最终融合为一个开源实现 NET 5 0 25 在 NET Framework 4 6 中 新的 JIT 编译器取代了前者 21 26 其他 C 编译器 其中一些包括公共语言基础结构和 NET 类库的实现 微軟的Rotor项目 Rotor Project 目前稱為Shared Source Common Language Infrastructure 英语 Shared Source Common Language Infrastructure 提供了通用语言运行库 Common Language Runtime 的實作與C 編譯器 但是Shared Source Common Language Infrastructure在2006年的2 0版後就停止了 由Microsoft贊助的Mono 项目提供了C 編譯器 它提供了一个开源 C 编译器 一个完整的 CLI 开源实现 同時也接近百分之百地實作了 NET Framework类库 而Mono後來衍伸出由微軟認可的第三方套件Xamarin Dot GNU 專案 现已停产 也提供了另一個自由版本的C 編譯器 也提供了 NET Framework类库的實作 游戏引擎 Unity 使用C 作为其主要脚本语言 由于Microsoft 捐赠了 24 000 美元 Godot 游戏引擎实现了一个可选的 C 模块 参考文献 编辑 Welcome to C 11 2022年12月10日 2 0 2 1 The Roslyn NET compiler provides C and Visual Basic languages with rich code analysis APIs dotnet roslyn November 13 2019 2021 08 16 原始内容存档于2021 02 22 通过GitHub CoreCLR is the runtime for NET Core It includes the garbage collector JIT compiler primitive data types and low level classes dotnet coreclr November 13 2019 2021 08 16 原始内容存档于2019 10 14 通过GitHub Rich Hickey Q amp A by Michael Fogus 2017 01 11 原始内容存档于2017 01 11 What s new in C 10 2022 02 16 原始内容存档于2022 02 08 C Language Specification PDF 4th Ecma International June 2006 2012 01 26 原始内容 PDF 存档于2012 12 02 7 0 7 1 Using C 3 0 from NET 2 0 Danielmoth com 2007 05 13 2012年10月4日 原始内容存档于2012 09 29 存档副本 2018 09 06 原始内容存档于2018 01 22 9 0 9 1 9 2 9 3 存档副本 2018 09 06 原始内容存档于2018 01 22 What s new in C 10 docs microsoft com 2021 11 10 原始内容存档于2022 02 08 美国英语 11 0 11 1 Visual Studio 2022 version 17 0 Release Notes docs microsoft com 2022 06 24 原始内容存档于2022 08 06 What s new in C 10 docs microsoft com 2021 11 10 原始内容存档于2022 02 08 美国英语 An Introduction to C Generics 2020 09 25 原始内容存档于2019 09 24 Anonymous Methods C 2008 10 24 原始内容存档于2008 04 17 Covariance and Contravariance in Delegates C 2008 10 24 原始内容存档于2008 10 12 Tim Anderson C pulling ahead of Java Lead architect paints rosy C picture Reg Developer The Register 2006 11 14 2007 01 20 原始内容存档于2007 01 21 LINQ Microsoft MSDN 2007 2007 08 13 原始内容存档于2007 01 16 英语 The Mellow Musings of Dr T What is a collection 2008 10 24 原始内容存档于2008 12 18 Partial Methods 2007 10 06 原始内容存档于2007 10 16 一覽 C 7 0 中的新功能 2016 09 14 原始内容存档于2018 10 02 21 0 21 1 The RyuJIT transition is complete microsoft com June 19 2018 July 20 2021 原始内容存档于July 19 2019 Managed Execution Process microsoft com July 20 2021 原始内容存档于December 23 2017 coreclr src jit github com July 20 2021 原始内容存档于January 9 2019 C Guide docs microsoft com 2017 11 20 原始内容存档于2022 08 13 5 0 8 microsoft com July 20 2021 原始内容存档于April 23 2020 Mitigation New 64 bit JIT Compiler microsoft com July 20 2021 原始内容存档于April 5 2018 外部連結 编辑 英文 C Language Specification MSDN 页面存档备份 存于互联网档案馆 英文 ECMA 334 C Language Specification pdf 英文 ISO IEC 23270 2003 C Language Specification 页面存档备份 存于互联网档案馆 英文 Visual Studio Code 页面存档备份 存于互联网档案馆 英文 Download NET 页面存档备份 存于互联网档案馆 Visual C NET入門 MSDN 页面存档备份 存于互联网档案馆 MCS Mono C 編譯器 页面存档备份 存于互联网档案馆 Visual Studio Community 页面存档备份 存于互联网档案馆 Visual C Logo 页面存档备份 存于互联网档案馆 C 教學 页面存档备份 存于互联网档案馆 C 教材目錄 页面存档备份 存于互联网档案馆 取自 https zh wikipedia org w index php title C amp oldid 75592412, 维基百科,wiki,书籍,书籍,图书馆,

文章

,阅读,下载,免费,免费下载,mp3,视频,mp4,3gp, jpg,jpeg,gif,png,图片,音乐,歌曲,电影,书籍,游戏,游戏。