C♯
C♯
C#是微软推出的一种基于.NET框架和后来的.NET的、面向对象的高级编程语言。C#是一种由C和C++衍生出来的面向对象的编程语言。它在继承C和C++强大功能的同时去掉了一些它们的复杂特性,使其成为C语言家族中的一种高效强大的编程语言。C#以.NET框架类库作为基础,拥有类似Visual Basic的快速开发能力。C#由安德斯·海尔斯伯格主持开发,微软在2000年发布了这种语言,希望借助这种语言来取代Java。C#已经成为Ecma国际和国际标准组织的标准规范。
命名.
C#的发音为“C sharp”,“#”读作“sharp”(),命名启发于音乐上的音名“C♯”,在音乐中“C♯”表示C升半音,为比C高一点的音节,且“#”形似4个加号,微软借助这样的命名,以表示C#在一些语言特性方面对C++的提升的意思。
由于显示器(标准字体、浏览器等)的技术限制,且大部分的键盘配置上不存在升记号(♯),所以井号(#)被用于此程式语言的名称中,约定在ECMA-334 C#语言规范中。
设计目标.
ECMA标准列出的C#设计目标:
-{H|zh-cn:重定向;zh-tw:重新导向;}-
历史.
原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++ 的影响。
语言特性.
相对于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使用具化生成泛型参数,它允许优化和保存类型信息。
泛型类中,可以用where关键字对参数类型实现约束。例如:
class Node
where T : Stack, IComparable, new(), class
where V : Stack, struct
上述表示T和V必须是Stack类或其派生类,T必须继承了IComparable接口、有无参构造函数、是引用类型;V必须是值类型。
泛型不仅能作用在类上,也可单独用在类的方法上,称为“泛型方法”。
泛型类的静态成员变量在相同封闭类间共享,不同的封闭类间不共享。
泛型类中的方法重载,参数类型T和V在运行时确定,不影响这个类通过编译。C#的泛型是在实例的方法被调用时检查重载是否产生混淆,而不是在泛型类本身编译时检查。特别地,当一般方法与泛型方法具有相同的签名时,会覆盖泛型方法。
静态类别.
静态类别它不能被实例化,并且只能有静态成员。这同很多过程语言中的模块概念相类似。
迭代器.
一种新形式的迭代器它提供了函数式编程中的generator,使用codice_1
类似于Python中使用的codice_2
// Method that takes an iterable input (possibly an array)
// and returns all even numbers.
public static IEnumerable GetEven(IEnumerable numbers)
foreach (int i in numbers)
if (i % 2 == 0) yield return i;
注意事项:
匿名方法.
匿名方法类似于函数式编程中的闭包。匿名方法是通过使用 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 == ...)
// ...
});
委托的协变和逆变.
委托签名的协变和逆变,
属性访问器可以被单独设置访问级别.
例子:
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
可空类型.
可空类型(跟个问号,如codice_3)允许设置codice_4给任何类类型。
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)");
??运算子.
(codice_5):如果左运算数表达式的值不为空值时回传该值,如果为空值则返回右运算数表达式的值。
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.
Linq.
语言集成查询(,缩写:LINQ): 上下文相关关键字"codice_6, codice_7, codice_8"可用于查询SQL、XML、集合等。这些标识符在LINQ上下文中被作为关键字,但是它们的增加不会破坏原有的名为codice_6、codice_7或codice_8的变量。
类型初始化器.
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 };
假设codice_12实现了codice_13且有一个codice_14方法method
匿名类型.
var x = new { Name = "James" };
局部变量类型推断.
局部变量类型推断:var x = new Dictionary 10;
)
可写作
listOfFoo.Where(x => x.Size > 10);
编译器翻译Lambda表达式为强类型委托或强类型表达式树。
注意事项:
自动化属性.
编译器将自动生成私有变量和适当的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();
注意事项:
分部方法.
允许代码生成器生成方法声明作为扩展点,如果有人在另一个部分类实现了它才会被包含于原代码编译。
例子:
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-{zh:修饰字;zh-hk:修饰字;zh-cn:关键字}-。
public interface IComparer
int Compare(T left, T right);
public interface IEnumerable : IEnumerable
IEnumerator GetEnumerator();
C# 6.0的特性.
表达式主体(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 的引数
弃元.
元组/对象的解构:
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;
对具有 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# 9的特性.
新的「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)中或是属性初始化式子中赋予其值,如果尝试在其他地方设定该属性的值,在编译时便会遭编译器阻止。
范例如下:在这个范例中,建立了一个codice_15类型,并且属性codice_16与codice_17只能在初始化时赋予其值。
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之后,最上层陈述式的程式码不需要包含namespace以及class,可将其简化为:
using System;
Console.WriteLine("Hello World!");
//或者简化为一行语句:
System.Console.WriteLine("Hello World!");
注意, 一个程序中, 只能有一个文件使用顶级语句, 并且顶级语句必须位于命名空间或类型定义之前。
lambda弃元参数.
Func zero = (_, _) => 0;
Func func = delegate (int _, int _) { return 0; };
在 C# 9 之前,即便不使用的 Lambda 参数也需要给它命名。C# 9 支持弃元参数一方面简化了命名,另一方面也节省了内存分配。更重要的是它使得编程的意图更明确,让人一看就知道这个参数是不用的,增强了代码的可读性和可维护性。
只能初始化的设置器.
Init only setters,只能通过对象初始化进行赋值的属性。
public class InitDemo
// 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* 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
class Student : Person
模块初始化代码.
ModuleInitializerAttribute 为组件 (assembly) 定义初始化代码, 当初始化/加载时执行, 可以类比类的静态构造函数, 但是是组件级别的。
静态 lambda 表达式.
static 修饰符添加到 lambda 表达式或匿名方法 。这将无法捕获局部变量或实例状态,从而防止意外捕获其他变量。
分部方法扩展.
移除了分部方法的下述限制:
初始化表达式的简化.
如果创建对象的类型已知时,可以在new表达式中省略该类型。
Point p = new(1, 1);
Dictionary dict = new();
Point[] points = { new(1, 1), new (2, 2), new (3, 3) };
var list = new List { 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 GetEnumerator(this IEnumerator enumerator) => enumerator;
class Program
static void Main(string[] args)
IEnumerator enumerator = new Collection {"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;
class Program
static void Main(string[] args)
var person1 = new Person("Alice", 40);
var inRange = person1 switch
(_, "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
(_, "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
(_, "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 "10",
_ => "not 10"
Console.WriteLine(n10); // 10
C# 10的特性.
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 的话,直接在文件开头写:codice_18
常量字符串插值.
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):
var x = Foo;
x(); // hello
自然委托类型.
lambda 可自动创建自然委托类型,于是不再需要写出类型:
var f = () => 1; // Func
var g = string (int x, string y) => $"{y}{x}"; // Func
var h = "test".GetHashCode; // Func
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特性。
在方法上指定 AsyncMethodBuilder.
在方法上用 [AsyncMethodBuilder(...)],来使用自己实现的 async method builder,代替自带的 Task 或者 ValueTask 的异步方法构造器。有助于实现零开销的异步方法。
line 指示器支持行列和范围.
以前 #line 只能用来指定一个文件中的某一行,现在可以指定行列和范围:
// 比如 #line (1, 1) - (2, 2) 3 "test.cs"
嵌套属性模式匹配改进.
以前在匹配嵌套属性的时候需要这么写:
现在只需要简单的:
改进的字符串插值.
实现接近零开销的字符串插值。
Source Generator v2.
包括强类型的代码构建器,以及增量编译的支持等
C# 11的特性.
泛型属性.
C# 11 开始支持属性(attribute)为泛型类,即允许声明基类为codice_19的泛型类:
静态接口方法.
C# 11 开始允许接口中定义静态方法(包括运算符重载方法),实现该接口的类必须包含该静态方法:
public interface IGetNext where T : IGetNext
static abstract T operator ++(T other);
无符号右移运算符 codice_20.
新增无符号右移运算符 codice_20,用于对带符号数进行逻辑右移。
泛型数学支持.
对泛型及其对象进行数学操作的支持。基于静态接口方法特性,自 .NET 8.0 起,在codice_22命名空间中提供数学运算相关泛型接口,以支持泛型的运算操作:
public static TResult Sum(IEnumerable values)
where T : INumber
where TResult : INumber
TResult result = TResult.Zero;
foreach (var value in values)
result += TResult.Create(value);
return result;
字符串内插中的换行符.
允许内插字符串中codice_23与codice_24内的文本跨多个行
原始字符串文本.
原始字符串文本以 codice_25 开始并以 codice_25 结束,允许多行字符串,若为多行字符串则以单独的一行 codice_25 结束,且字符串的缩进以末尾的 codice_25 的起始位置为基准。原始字符串文本不进行任何转义操作,但允许字符串内插(开头的 $ 数量代表内插所需要的花括号数):
var x = 1;
var y = 2;
var code1 = """int i = 0;""";
var code2 = $"""int x = {x};""";
var code3 = $$"""
#include
int main(void) {
const char *s = "{y} = "; // {y} = 2
return 0;
""";
Console.WriteLine($"code1:\n{code1}\n");
Console.WriteLine($"code2:\n{code2}\n");
Console.WriteLine($"code3:\n{code3}\n");
UTF-8 字符串字面量.
可以对字符串字面量指定 codice_29 后缀来指定 UTF-8 字符编码的字符串字面量,其类型为codice_30:
列表模式.
使用codice_31和codice_32可以定义列表模式,用于模式匹配:
int[] numbers = { 1, 2, 3 };
Console.WriteLine(numbers is [1, 2, 3]); // True
Console.WriteLine(numbers is [1, 2, 4]); // False
Console.WriteLine(numbers is [1, 2, 3, 4]); // False
Console.WriteLine(numbers is [0 or 1, = 3]); // True
数值 codice_33 和 codice_34.
C# 11 起 codice_35 和 codice_36 类型的别名分别为 codice_33 和 codice_34(C# 9 中它们仅被认为是“相似”的)。
改进了方法组向委托的转换.
优化了方法组向委托转换的性能。例如下述代码中,在 C# 11 前,codice_39 比 codice_40 性能更高:
static readonly List Numbers = Enumberable.Range(0, 100).ToList();
public int Sum()
return Numbers.Where(x => Filter(x)).Sum(); // 50;
程序的执行.
C#通常不被编译成为能够直接在计算机上执行的二进制本地代码。与Java类似,它被编译成为中间代码(Microsoft Intermediate Language),然后通过.NET Framework的虚拟机——被称为-{zh-hans:通用语言运行库;zh-hant:通用语言执行层}-——执行。
所有的.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程式.
下面是一个在-{zh:命令列;zh-hans:命令行;zh-hant:命令提示字元}-上输出Hello World的小-{zh:程序;zh-hans:程序;zh-hant:程式}-,这种-{zh:程序;zh-hans:程序;zh-hant:程式}-通常作为开始学习-{zh:程序;zh-hans:程序;zh-hant:程式}-语言的第一个步骤:
using System;
namespace ConsoleApp1
class Program
static void Main(string[] args)
Console.WriteLine("Hello World!");
实现.
微软正在引领开源参考 C# 编译器和工具集的开发。 第一个编译器 Roslyn编译成中间语言(IL),第二个编译器 RyuJIT, 是一个 JIT(即时)编译器,它是动态的,进行动态优化并编译将 IL 转换为 CPU 前端的本机代码。 RyuJIT 是开源的,用 C++ 编写。 Roslyn 完全是用 托管代码 (C#)编写的,已经开放并且功能以 API 的形式出现。因此,它使开发人员能够创建重构和诊断工具。 官方实现的两个分支是 .NET Framework(闭源,仅限 Windows)和 .NET Core(开源,跨平台);它们最终融合为一个开源实现:.NET 5.0。 在 .NET Framework 4.6 中,新的 JIT 编译器取代了前者。
其他 C# 编译器(其中一些包括公共语言基础结构和 .NET 类库的实现):
游戏引擎 Unity 使用C# 作为其主要脚本语言。由于Microsoft 捐赠了 24,000 美元, Godot 游戏引擎实现了一个可选的 C# 模块。