赞
踩
C#是微软推出的一种基于.NET框架和后来的.NET的、面向对象的高级编程语言。C#是一种由C和C++衍生出来的面向对象的编程语言。它在继承C和C++强大功能的同时去掉了一些它们的复杂特性,使其成为C语言家族中的一种高效强大的编程语言。C#以.NET框架类库作为基础,拥有类似Visual Basic的快速开发能力。C#由安德斯·海尔斯伯格主持开发,微软在2000年发布了这种语言,希望借助这种语言来取代Java。C#已经成为Ecma国际和国际标准组织的标准规范。
结构化、面向对象、泛型 | |
语言家族 | C |
設計者 | 微软 |
實作者 | 微软 |
2000年 | |
当前版本 |
|
操作系统 | Windows、Linux、Mac OS X 、 Android |
許可證 |
|
文件扩展名 | .cs , .csx |
網站 | |
主要實作產品 | |
.NET、.NET框架、Mono、DotGNU | |
衍生副語言 | |
Cω、Spec#、Polyphonic C# | |
啟發語言 | |
C++、Java、Eiffel、Modula-3、Object Pascal | |
影響語言 | |
Clojure、D語言、F#、Java 5、Nemerle、Vala |
C#的发音为“C sharp”,“#”读作“sharp”(/ʃɑːp/),命名启发于音乐上的音名“C♯”,在音乐中“C♯”表示C升半音,為比C高一点的音节,且“#”形似4个加号,微软借助这样的命名,以表示C#在一些语言特性方面对C++的提升的意思。
由於顯示器(標準字體、瀏覽器等)的技術限制,且大部分的鍵盤配置上不存在升記號(♯),所以井號(#)被用於此程式語言的名稱中,約定在ECMA-334 C#語言規範中。
ECMA标准列出的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 | Visual Studio .NET 2003 | ||
C# 2.0 | 2006年6月 | 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) | 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 Core 2.0 | Visual Studio 2017 version 15.3 |
C# 7.2 | 否 | 否 | 建议草案 | 2017年11月 | .NET Framework 4.7.1 | Visual Studio 2017 version 15.5 |
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 |
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 |
C# 9.0 | 否 | 否 | 建议草案 (页面存档备份,存于) | 2020年9月 | .NET 5 | Visual Studio 2019 version 16.8 |
C# 10.0 | 否 | 否 | 建议草案 (页面存档备份,存于) | 2021年11月 |
| Visual Studio 2022 version 17.0 |
C# 11.0 | 否 | 否 | 建议草案 (页面存档备份,存于) | 2022年8月 |
| Visual Studio 2022 version 17.1 |
针对于.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<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; } }
注意事项:
匿名方法类似于函数式编程中的闭包。匿名方法是通过使用 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 }
可空类型(跟个问号,如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发布于2007年10月17日,是.NET Framework 3.5的一部分,它的新特性灵感来自于函数式编程语言,如:Haskell和ML,并广泛地引入了Language Integrated Query(LINQ)模式到通用語言運行庫中e.
语言集成查询(英語:,缩写:LINQ): 上下文相关关键字"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
var x = new { Name = "James" };
局部变量类型推断:
var x = new Dictionary<string, List<float>>();
等同于
Dictionary<string, List<float>> x = new Dictionary<string, List<float>>();
它只是一个语法糖,这个特性被匿名类型声明时所需要
Lambda表达式(無函式名稱的物件方法在程式語言中的表達語法):
listOfFoo.Where( delegate(Foo x) { return x.Size > 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关键字,提供動態編程(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");
在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(); }
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();//只读属性 }
能夠直接宣告一個變數在它要傳入的地方,當成一個 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; } 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)); }
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; } }
记录类型, 是一种引用类型, 默认是不可变的。 记录类型的相等判断可以通过引用或者结构进行判断的。
// 默认不可变的记录类型 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存取子表示該屬性所屬類型僅能在建構函式(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!");
注意, 一个程序中, 只能有一个文件使用顶级语句, 并且顶级语句必须位于命名空间或类型定义之前。
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) 定义初始化代码, 当初始化/加载时执行, 可以类比类的静态构造函数, 但是是组件级别的。
static 修饰符添加到 lambda 表达式或匿名方法 。这将无法捕获局部变量或实例状态,从而防止意外捕获其他变量。
移除了分部方法的下述限制:
如果创建对象的类型已知时,可以在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 扩展方法, 返回一个 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
解决了 record 只能给 class 而不能给 struct 用的问题:
record struct Point(int X, int Y);
可以把 record 里的 ToString 方法标记成 sealed
无参构造函数使得new struct() 和 default(struct) 的语义不一样
var x = new { A = 1, B = 2 }; var y = x with { A = 3 };
这里 y.A 将会是 3 。
可以给整个项目启用 using,不需要每个文件都写一份。
以前写 namespace 还得带一层大括号。现在如果一个文件里只有一个 namespace 的话,直接在文件开头写:namespace MyNamespace;
const string x = "hello"; const string y = $"{x}, world!";
f = [Foo] (x) => x; // 给 lambda 设置 f = [return: Foo] (x) => x; // 给 lambda 返回值设置 f = ([Foo] x) => x; // 给 lambda 参数设置
此前 C# 的 lambda 返回值类型靠推导,C# 10允许在参数列表之前显式指定 lambda 返回值类型:
f = int () => 4;
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这个attribute,编译器会自动填充调用参数的表达式字符串,例如:
void Foo(int value, [CallerArgumentExpression("value")] string? expression = null) { Console.WriteLine(expression + " = " + value); }
当你调用 Foo(4 + 5) 时,会输出 4 + 5 = 9。这对测试框架极其有用
int y = 0; (var x, y, var z) = (1, 2, 3);
于是 y 就变成 2 了,同时还创建了两个变量 x 和 z,分别是 1 和 3 。
.NET 6中这个特性为preview特性。
在方法上用 [AsyncMethodBuilder(...)],来使用自己实现的 async method builder,代替自带的 Task 或者 ValueTask 的异步方法构造器。有助于实现零开销的异步方法。
以前 #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 }) { ... }
实现接近零开销的字符串插值。
包括强类型的代码构建器,以及增量编译的支持等
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)。现在有一些独立的实现正在进行,包括:
下面是一個在上輸出Hello World的小,這種通常作為開始學習語言的第一個步驟:
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# 模块。
This article is issued from Wikipedia. The text is licensed under Creative Commons - Attribution - Sharealike. Additional terms may apply for the media files.
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。