C#編程語言及.NET 平臺快速入門指南

e-mail: hamlet.jiang@live.com
 

⼀、C#,CLR,IL,JIT概念 以及 .NET 家族

(⼀)基礎概念

C# (念做 C Sharp) 是在CLR上實現的一種編程語言,也是.NET平臺上最通用的編程語言,它在語法上借鑑了Java和C++風格,但更爲精簡。Borland Turbo Pascal編譯器的主要做者安德斯·海爾斯伯格(Anders Hejlsberg)是C#與.NET平臺的創始人。本文詣在爲初次接觸C#和.NET平臺的用戶提供較全面的路線指引,也爲早期.NET開發人員介紹當代.NET平臺的新特性。
 
相對於 C 和 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++模版中被用於類型參數。
八、屬性支持,使用相似訪問成員的方式調用。
九、完整的反射支持。
 
 CLR-Common Language Runtime 意爲公共語⾔運⾏庫,它是⼀個可由多種不一樣編程語⾔使⽤的運⾏庫,只要是⾯向 CLR 的編譯器編譯的編程語⾔都被 CLR ⽀持。
 
 IL-Intermediate Language,意爲中間語⾔,⾯向 CLR 的編程語⾔被編譯爲IL代碼,IL代碼也被稱爲託管代碼,它是與 CPU ⽆關的機器語⾔,是⼀種⾯向對象的機器語⾔。每⼀個 IL 代碼⽂件被稱爲託管模塊(managed module)。託管模塊是 ⼀個32位或是64位可移植執⾏體⽂件,它們須要CLR才能執⾏。
 
 每一個託管模塊帶有相應的元數據(metadata),元數據描述模塊中定義的內容,⽐如類型及成員、導⼊的類型及成員。每 個託管模塊由操做系統頭信息、CLR頭(記錄版本、⼊口⽅法等)、元數據、IL代碼(CLR在運⾏時將IL編譯成本地CPU 指令)。 ⼀個.NET程序集是由⼀個或者多個託管模塊和資源⽂件組成,程序集是⼀個或是多個託管模塊的邏輯分組,是最⼩的可重用、安全性及版本控制單元。
 
 JIT-just-in-time,意爲CLR對IL代碼進⾏即時編譯的過程,CLR擁有進⾏JIT過程的編譯器(JITComiler),它將要調⽤的 IL 代碼編譯爲本地 CPU 指令。
 
.NET CORE 即將像C++同樣支持 Intel CPU SIMD 指令集(從SSE到AVX2),參考下列資料:
 

(二).NET 家族

本文將Windows上的.NET Framework稱爲經典 .NET,由公共語⾔運⾏庫(CLR)和類庫(FCL --Framework Class Library)構成。
.NET Core 是 經典.NET 的跨平臺實現,.NET Standard是 .NET Core 和 .NET Framework之間的通用庫。
Mono是一個由Xamarin公司所主持的開源項目。該項目的目標是建立一系列匹配ECMA標準的.NET工具,包括C#編譯器和通用語言架構。
ML.Net 是.NET Core上實現的AI開發框架。
 
開發Windows應用建議選擇經典.NET (v.4.x)或 .NET Core 3.0+ (Winfrom和WPF);
開發Linux上的微服務、Web服務、docker容器服務建議使用.NET Core (v.2.2.x、v.3.0.x) ;
開發跨平臺手機應用建議使用.NET Xamarin框架(支持ios,Aandroid);
 
.NET Core 3.0 正式公佈:新特性詳細解讀
 
注:Visual Studio 2019 支持用戶使用以上任何一個框架開發應用,並內置相關應用場景的項目模板。
Visual Studio 2017支持.NET v.4.x 及.NET Core 2.2的項目開發。
 
微軟公司在2014年開源了Roslyn編譯器,隨後成立了.NET 開源基金會,並在 Github上以MIT協議公開了.NET源代碼。詳情參考: https://github.com/dotnet
 
.NET 5 將在2020年推出,它將統一目前全部的 .NET 分支。

上圖爲.NET 5 架構圖html

上圖是 .NET 發佈路線圖linux

 

一家名爲iolevel的公司推出了peachpie編譯器(https://www.peachpie.io/)致力於將PHP語言帶到.NET平臺。他們以前是一所大學團體(位於布拉格的查爾斯大學),推出過名爲Phalanger的編譯器( https://github.com/DEVSENSE/Phalanger)將一部分Facebook的開源代碼轉換爲.NET代碼來執行。這些均可以證實.NET平臺的先進性。點擊這裏瞭解一些peachpie的背景:https://kb.cnblogs.com/page/138573/android

2、C# 語言要點

(一)基元類型

C#類型 FCL 類型 說明
Sbyte System.Sbyte 有符號8位值 (⼀位即1bit,8bit即1byte,下同)
byte System.Byte ⽆符號8位值
Short System.Int16 有符號16位值
ushort System.UInt16 無符號16位值
int System.Int32 有符號32位值
uint System.UInt32 無符號32位值
Long System.Int64 有符號64位值
ULong System.UInt64 無符號64位值
char System.Char 16位Unicode字符
Float System.Single IEEE32位浮點
Double System.Double IEEE64位浮點
Bool System.Boolean ⼀個true/false值
Decimal System.Decimal 128位⾼精度浮點值
String System.String ⼀個字符數組
Object System.Object 全部類型的基類型
 

(二)引用類型和值類型

CLR⽀持引⽤類型和值類型。 引⽤類型老是從託管堆上分配,C#的new操做符會返回對象的內存地址。結構與枚舉都是值類型,與引⽤類型相⽐,值類型是⼀種輕量級的類型,值類型實例是在線程的堆棧上分配,值類型不須要內存指針,不須要垃圾收集處理。全部類型 都是System.Object派⽣,全部值類型都是由System.ValueType抽象類派⽣。
 

(三) 值類型的裝箱與拆箱:

當須要⼀個值類型進⾏實例引⽤時產⽣裝箱(boxing) ,裝箱過程是從託管堆中分配內存,並將值類型字段複製到新分 配的堆內存,而後返回新對象的引⽤。 
裝箱情景:
Struct Point{public int32 x,y;}
 
 Public sealed class Program
 { 
    Public static void Main()
     {
         ArrayList a = new ArrayList();
         Point p; 
         For(int32 i =0;i<10;i++) 
         {
             p.x = p.y = i;
             a.Add(p);//這⾥產⽣裝箱,Add⽅法⼊參必須是Object類型,⽽Object類型是⼀個引⽤類型,值類型P要被裝箱爲引⽤ 類型。
         }         
     } 
}
 
上例中,ArrayList內的p元素是引⽤類型,與原 Point P 結構脫離了關係。
 
 拆箱情景(unboxing): 
Point p2 =(Point)a[0];//這⾥產⽣拆箱
 
拆箱是獲取已裝箱對象各個字段的地址(拆箱關鍵),並將已經裝箱的對象的字段值複製到新的值類型變量的字段。拆 箱時只能將對象拆箱爲它裝箱時的類型。
 
⼿動控制裝箱的速度將⽐編譯器裝箱的速度快。 
如:
 1)Int32 v =5;Console.writeLine(「{0}{1}{2}」,v,v,v);
 2)Int32 v=5;object o =v(⼿動裝箱);Console.writeLine(「{0}{1}{2}」,o,o,o)//這個⽅法快

(四)類型、類成員、接口

類型基礎
類型:是能夠在類型內部嵌套地定義其餘類型的邏輯單位。
類型的成員種類:常量、字段、實例構造器、類型構造器(靜態構造)、⽅法、操做符重載、轉換操做符、屬性、靜態 事件、實例事件。
訪問修飾符表:
名稱 用做類 用做類成員

Publicios

該類型對全部程序集是可見的 成員能夠由全部程序集的全部⽅法訪問
Protected internal   成員能夠由所在類型及其嵌套類型、全部派⽣類型 (不限程序集)、類型所在程序集的全部⽅法訪 問。
Internal 該類型僅在程序集內部可見以及友元程序 集可見 成員可由當前程序集中的全部⽅法訪問
Protected   成員只能由定義該成員類型中的⽅法、該類型的所 有嵌套類型的⽅法、或者該類型的⼀個派⽣類型 (不限程序集)的⽅法訪問
Private   成員只能由定義該成員的類型中的⽅法或者該類型 的全部嵌套類型中的⽅法訪問

 

組件版本控制修飾符表:git

名稱 用做類 用做方法、屬性、事件 ⽤做常量/字段
Abstract 表⽰該類型不能構建實例 表⽰在構建派⽣類的實例以前派⽣類 型必須實現這個成員  
Virtual   表⽰這個成員能夠由派⽣類型重寫  
Override   表⽰派⽣類型重寫了基類型的成員  
Sealed 表⽰該類型不能⽤做基類 表⽰該成員不能被派⽣類型重寫  
new 應⽤於嵌套類型、⽅法、屬性、事件、常量或字段時,表⽰該成員與基類中相似的成員沒有關係  

 

靜態類(static class):靜態類是不須要實例化,僅擁有靜態成員的類型。靜態類不⽀持接⼜,這是由於只有使⽤類的實 例的時候才調⽤類的接⼜⽅法。靜態類型只包括靜態成員,靜態類本⾝不能⽤做字段、⽅法參數或者局部變量。
 
部分類(partial class):爲了將⼀個類分佈在多個⽂件中編輯⽽採⽤partial修飾符,它們在編譯後成爲⼀個類。
 
索引器(indexer):索引器是⼀種參數化的成員屬性。索引器不⽀持靜態類型。索引器的做⽤是爲類型向外界間接提供 內部的集合成員。
例:
public object this[int x]{get;set;},public object this[int x,int y]{get;set;}
 
可變參數⽅法:以params關鍵字修飾的參數稱爲可變參數,它容許輸⼊數量不定的參數來調⽤⽅法。
例:
 Public static double GetAvg(params double[] list){…}; GetAvg(1,2,12,4,3.2);GetAvg(1,57.3);
 
基類初始化(initializer)調⽤:⼦類在實例化時能夠⼀並調⽤基類的構造函數。這在多個類共享基類構造函數設置的⼀ 些公共成員屬性時更便利。
例:
Public class ClassA
{
    public ClassA(int a,string b){…}
}
 
Public class ClassB:ClassA
{
    public ClassB(int a,string b,bool c):base(a,b){…}
}
 
類型的私有構造函數常被⽤於只經過靜態⽅法和字段來提供功能的類型。採⽤私有構造函數的類不能被外部類實例化, 但能夠在內部實例化。
 
 靜態構造函數⽤於初始化靜態成員,也只能訪問靜態成員,無論類型被實例化多少次,靜態構造函數只執⾏⼀次。
 
C# 特性標記的使用
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Class, Inherited = true)]
public class CustomerAttribute:Attribute
{
      public String Name{get;set;}   
}
 
使用反射獲取特性標記值
[CustomerAttribute(){Name="Sample"}]
public class Sample(){}
Sample o = new Sample();
Type ot = typeof(o);//typeof(t)
ot.GetCustomAttributes();
 
C# 匿名擴展方法
public class A
{
      public A();
     public void M1();
}
 
public static class M
{
      public static M2(this A a )
      {
            //do sth.
      }
}
 

(五) 集合類型 Array\ArrayList\List\HashTable(哈希表)\Dictionary(字典)\Stack(堆棧)\Queue(隊列)

Array類型:是實現數組的基類,只有系統和編譯器能夠派⽣。Array提供CreateInstance⽅法進⾏後期綁定,沒有公共構 造函數。如下都是聲明數組的⽅式:
Array my1DArray=Array.CreateInstance( typeof(Int32), 5 ); 
Int32[] my2DArray = new Int32[5]{1,2,3,4,5}
 
ArrayList類型:是⼤⼩按需⾃動增長的Array實現,實現了IList接口。如下是ArrayList常見⽤法:
ArrayList myAL = new ArrayList(); 
myAL.Add("Hello");
myAL.Add("World"); myAL.Add("!");
 
HashTable: 表⽰鍵/值對的集合,這些鍵/值對根據鍵的哈希代碼進⾏組織。
例:
public static void Main() {
// Creates and initializes a new Hashtable.
Hashtable myHT = new Hashtable();
myHT.Add("First", "Hello");
myHT.Add("Second", "World");
myHT.Add("Third", "!");
// Displays the properties and values of the Hashtable.
Console.WriteLine( "myHT" );
Console.WriteLine( " Count: {0}", myHT.Count );
Console.WriteLine( " Keys and Values:" );
PrintKeysAndValues( myHT );
}
public static void PrintKeysAndValues( Hashtable myHT ) {
Console.WriteLine( "\t-KEY-\t-VALUE-" );
foreach ( DictionaryEntry de in myHT )
Console.WriteLine("\t{0}:\t{1}", de.Key, de.Value);
Console.WriteLine();
}
 
Dictionary:是HashTable的泛型實現
 
Stack:表⽰對象的簡單的後進先出⾮泛型集合。Stack 的容量是 Stack 能夠保存的元素數。Stack 的默認初始容量爲 10。 向 Stack 添加元素時,將經過從新分配來根據須要⾃動增⼤容量。Stack常被看成循環緩衝區。
 
Queue(隊列):是表⽰對象的先進先出集合,與Stack相反。隊列在按接收順序存儲消息⽅⾯⾮常有⽤,以便於進⾏順 序處理。此類將隊列做爲循環數組實現。存儲在 Queue 中的對象在⼀端插⼊,從另⼀端移除。
Queue 的容量是 Queue 能夠保存的元素數。Queue 的默認初始容量爲 32。向 Queue 添加元素時,將經過從新分配來根據 須要⾃動增⼤容量。
 

(六)泛型

泛型(generic)是CLR與編程語⾔提供的⼀種實現「算法重⽤」的機制。
例:
 List sl = new List();sl.add(DateTime.Now);sl.add(DateTime.MinValue);
 
泛型對象設計⽤於管理在類型上成家族的集合,例如設計⼀個⼯⼚類型⽤於建立或修改基於某個接口演變的多個⼦類型 的對象。
 
例:
/// <summary>
/// 爲安全成員對象提供公共服務
/// </summary>
public abstract class SecurityMemberService<T> where T:ISecurityMember
{
    public abstract T MemberLogin(string memberUserName,string memberPassword);
    public abstract T MemberLogin(string memberEmail,string memberPassword);
    public abstract bool MemberLogout(T member);
    public abstract T CreateMember(T obj,SecurityMemberInfo info);
    public abstract bool DeleteMember(T member);
    public abstract T FindMemberByUserName(string userName);
    public abstract T FindMemberByEmail(string email);
    public abstract bool LockMember(T member);
    public abstract bool UnlockMember(T member);
    public abstract bool ChangePassword(string memberName, string oldPassword,string newPassword);
    public abstract bool ChangePasswordQuestionAndAnswer(T member);
    public abstract bool ResetPasswordAndUpdate(T member);
}
 
在上例中,SecurityMemberService類型封裝了⼀般對ISecurityMember類型的處理⽅法,類型參數T能夠是任意 實現了ISecurityMember接⼝的類型,這樣對這些類型的⼀般處理並不須要建立額外對應的⼯⼚類型。 注意:泛型類SecurityMemberService有⼀個對類型參數T的約束,它由where關鍵字指定。
 
在⾮泛型類中也能夠有泛型⽅法成員,一樣泛型⽅法也可有類型約束。
例:
Public class A
{
Void M1<T>(T obj){obj.ToString();}
Void M2<T>(T obj)where T:ClassB {obj.ToString();}
}
 
委託也能夠被設計成泛型,由於委託也能夠被看成⽅法的⼀種定義形式,即委託自己描述的是回調⽅法的定義。
例:
Delegate void EventHandler(Object sender,TEventArgs e)where TEventArgs:EventArgs;
上例定義的EventHandler要求回調⽅法中的參數e必須是EventArgs類型或是EventArgs的派⽣類型,TEventArgs 是⼀個類型參數,至關於常⻅的T。

(七)線程 (Threading、Lock、Monitor、Mutex)

線程概述:
線程分爲前臺線程和後臺線程,後臺線程不妨礙程序的終⽌。線程具備優先級,優先級⾼的線程會獲得更多的CPU時 間。多線程能夠提⾼對CPU時間的利⽤率,但會佔⽤更多的內存等資源。
 
線程安全:
Lock關鍵字能夠將⼀段代碼定義爲互斥段。互斥段在⼀個時刻內只容許⼀個線程進⼊執⾏,⽽其餘線程必須等待。若是 有⼀些任務每次只能交給⼀個線程去操做,就可使⽤Lock關鍵字將代碼定義爲互斥段。
例:
Lock(this) 
{
     //do anything 
}
 
Monitor 類經過向單個線程授予對象鎖來控制對對象的訪問。對象鎖提供限制訪問代碼塊(一般稱爲臨界區)的能⼒。當 ⼀個線程擁有對象的鎖時,其餘任何線程都不能獲取該鎖。還可使⽤ Monitor 來確保不會容許其餘任何線程訪問正在由 鎖的全部者執⾏的應⽤程序代碼節,除⾮另⼀個線程正在使⽤其餘的鎖定對象執⾏該代碼。
 
例:
Queue myQueue = new Queue();
Monitor.Enter(myQueue);
//能夠在當前線程下對myQueue作任何操做。
Monitor.Exit(myQueue)//釋放鎖
 
爲了保證在異常狀況下仍可釋放鎖,Monitor.Exit()⽅法能夠放在finally塊⾥。調⽤Monitor.Pulse()⽅法會通知預備隊列中的 線程能夠⽴即便⽤釋放的對象。
 
Mutex類是同步基元。當兩個或更多線程須要同時訪問⼀個共享資源時,系統須要使⽤同步機制來確保⼀次只有⼀個線程 使⽤該資源。
Mutex只向⼀個線程授予對共享資源的獨佔訪問權。若是⼀個線程獲取了互斥體,則要獲取該互斥體的第⼆個線程將被掛 起,直到第⼀個線程釋放該互斥體。已命名的系統互斥體(Mutex)在整個操做系統中均可見,可⽤於同步進程活動。
 
與Monitor類不一樣,Mutex可與WaitHandle⼀起構成「等待機制」,Mutex還能夠穿越應⽤程序域。
例:
class Test
{
    // Create a new Mutex. The creating thread does not own the
    // Mutex.
    private static Mutex mut = new Mutex();
    private const int numIterations = 1;
    private const int numThreads = 3;
    static void Main()
    {
        // Create the threads that will use the protected resource.
        for(int i = 0; i < numThreads; i++)
        {
            Thread myThread = new Thread(new ThreadStart(MyThreadProc));
            myThread.Name = String.Format("Thread{0}", i + 1);
            myThread.Start();
        }
        // The main thread exits, but the application continues to
        // run until all foreground threads have exited.
    }
    private static void MyThreadProc()
    {
        for(int i = 0; i < numIterations; i++)
        {
            UseResource();
        }
    }
    // This method represents a resource that must be synchronized
    // so that only one thread at a time can enter.
    private static void UseResource()
    {
        // Wait until it is safe to enter.
        mut.WaitOne();
        Console.WriteLine("{0} has entered the protected area",
        Thread.CurrentThread.Name);
        // Place code to access non-reentrant resources here.
        // Simulate some work.
        Thread.Sleep(500);
        Console.WriteLine("{0} is leaving the protected area\r\n",
        Thread.CurrentThread.Name);
 
        // Release the Mutex.
        mut.ReleaseMutex();
    }
}
 

(八) C# 面向對象編程、繼承、多態、接口、委託、事件

基本概念
⾯向對象編程(Object –Oriented Programming,OOP),抽象、繼承和多態是OOP編程語⾔的三⼤要素。
 
繼承:類繼承的重要特性是,在但願出現基類型實例的任何地⽅,均可以替換成派⽣類型的實例。相似地,接口繼承容許在但願出現已命名接口類型的實例的任何地⽅,均可以替換成實現接口的⼀個類型的實現。
 
多態:指的是多個類型的對象對同⼀消息作出各⾃的處理。多態是⼦類對⽗類的⽅法進⾏重寫或替換⽽實現的。 
 
接口:接口是⼀組已命名的⽅法簽名,在接口內還能夠定義事件和屬性,它們在本質上也是⽅法。C# 要求接口⽅法標記爲 Public。接口的關鍵價值在於隱藏類型的設計細節,即外部對象不依賴當前對象的內部細節。
 
接口特性
接口⽅法的隱式實現:當⽅法簽名與繼承的接口中的簽名⼀致,而且是public或者是viture修飾的⽅法都視爲隱式實現了接口⽅法。
例:
Internal sealed class SimpleType:IDisposable
{
Public void Dispose(){Console.WriteLine(「Dispose」);}
}
 
接口⽅法的顯式實現:以接口類型名稱做爲⽅法前綴時,建立的是⼀個顯式接口⽅法實現(explicit interface method implementation,EIMI)。⼀個EIMI⽅法不容許標記訪問性(⽐如公共或私有),也不能被標記爲virture,因⽽也不能被重 寫。顯⽰接口⽅法會損害性能,應當謹慎使⽤。
例:
Internal sealed class SimpleType:IDisposable
{
Public void Dispose(){….}
Void IDisposable.Dispose(){….}//顯式
}
 
對顯式接口的調⽤,須要經過⼀個接口類型的變量來進⾏。
例:
SimpleType st = new SimpleType();
IDisposable d = st;
d.Dispose();
 
泛型接口有以下優勢:
一、使用接口方法變爲強類型。
二、泛型接口在操做值類型時,會減小裝箱操做。
三、類能夠實現同一個接口若干次,只要使用不一樣的類型參數。
例:
Public sealed class Number:IComparable<Int32>,IComparable<String>
{
Private int32 m_val =5;
 
//實現IComparable<Int32>
Public Int32 CompareTo(Int32 n){return m_val.CompareTo(n);}
 
//實現IComparable<String>
Public Int32 CompareTo(String s){return m_val.CompareTo(Int32.Parse(s));}
}
 
委託
委託是.NET中的回調機制。將一個方法綁定到一個委託時,C#和CLR容許引用類型的協變(covariance)和反協變(contra-variance)。協變是指一個方法能返回一個從委託的返回類型派生出來的類型。反協變是指一個方法的參數類型能夠是委託的參數類型的基類。但協變對於返回值類型或void的方法不適用。
例:
//MyCallback委託
Delegate object MyCallback(FileStream s);
 //SomeMethod⽅法 
String SomeMethod(Stream s);
 
上例中,SomeMethod的返回類型(String)繼承⾃委託返回類型(Object),這種協變是容許的。SomeMethod的參數類型
(Stream)是委託的參數類型(FileStream)的基類。這種反協變是容許的。
 
鏈式委託指的是⽤⼀個委託回調多個⽅法,即⼀系列委託對象組成的集合。Delegate的公共靜態⽅法Combine⽤於添加⼀ 個委託到委託鏈,Remove⽅法⽤於從鏈中刪除⼀個委託對象。在C#中內置的+=與-=操做符簡化了這些操做。
例:
Internal delegate void Feedback(int32 value);
Feedback fb1 = new Feedback(….);
Feedback fb2 = new Feedback(….);
fbChain =(Feedback)Delegate.Combine(fbChain,fb1);
fbChain =(Feedback)Delegate.Combine(fbChain,fb2);
 
⼀組委託是按順序執⾏的,若是他們帶有返回值,只能獲得最後⼀個委託的返回值,若是其間有委託⽅法出現致命錯誤,其它委託就⽆法執⾏。爲了克服這些問題,產⽣了MulticastDelegate類,它的GetInvocationList⽅法⽤於顯式調⽤鏈中的每 ⼀個委託,並使⽤符合⾃⼰需求的任何算法。MulticastDelegate類是特殊的類型,只能由系統派⽣,Delegate類已經具有了 MulticastDelegate的能⼒。
 
委託的便捷實現:
1. 不構造委託對象
例:
 internal sealed class AClass 
     public static void CallbackWithoutNewingADelegateObject()  
    { 
        ThreadPool.QueueUserWorkItem(SomeAsyncTask,5); 
    } 
   
   private static void SomeAsyncTask(Object o)
   {
       Console.WriteLine(o);
   } 
}
 
上例中ThreadPool類的靜態⽅法QueueUserWorkItem指望接收⼀個WaitCallback委託對象引⽤,該對象又包含⼀個 SomeAsyncTask⽅法引⽤。由於C#編譯器可以⾃⼰進⾏推斷,因此咱們能夠省略構造WaitCallback對象的代碼。
 
2. 不定義回調⽅法
例: 
internal sealed class AClass 
     public static void CallbackWithoutNewingADelegateObject() 
     {  
        ThreadPool.QueueUserWorkItem(delegate(Object obj){Console.WriteLine(obj);},5)  
     } 
上例中⽤了⼀段代碼塊替代了回調⽅法名,編譯器會⾃動在類中增長⼀個通過命名的基於此代碼塊的回調⽅法。
 
3. 不指定回調⽅法的參數
例:
button1.Click += delegate(Object sender,EventArgs e){MessageBox.Show(「The Button was clicked」);} 
//因爲上述⽅法中沒有⽤到sender與e兩個參數,可簡寫爲:
button1.Click+=delegate{MessageBox.Show(「 The Button was clicked」);}
 
4. 不須要將局部變量⼈⼯封裝到類中,便可傳給⼀個回調⽅法
 
事件
事件:在.NET中事件(event)是類的成員,與成員屬性和⽅法⼀樣。類型的事件,是對外提供的⾃⾝狀態的通知。外部類 型經過訂閱的形式與事件的發佈類型進⾏協做。將事件與處理⽅法關聯起來的是委託。.NET中⽤event關鍵指定特定的委託 來爲事件作出響應,這樣作能夠限制其它⽅法對委託的調⽤(在內部定義委託爲私有的,經過event公開,所以外部⽆法訪 問委託中的⽅法)。
 
設計線程安全的事件,必須顯⽰地控制事件的訂閱與註銷。
例:
internal class MailManager
{
    //建立⼀個做爲線程同步鎖的私有實例字段
    private readonly Object m_eventLock = new Object(); 
 
    //增長⼀個引⽤ 委託鏈表頭部的私有字段
    private EventHadler<NewMailEventArgs> m_NewMail;
 
    //增長⼀個事件成員
    public event EventHandler<NewMailEventArgs> NewMail
    {
        //顯式實現add
        add
        {
         //加私有鎖,並向委託鏈表增長⼀個處理程序以‘value’爲參數
        lock(m_eventLock){m_NewMail+=value;}  
       }
      //顯式實現remove
     remove 
     {
      //加私有鎖,並向委託鏈表移除⼀個處理程序以‘value’爲參數 
      lock(m_eventLock){m_NewMail -= value;}
      } 
    }
 
    //定義⼀個負責引起事件的⽅法,來通知已訂閱事件的對象事件已經發⽣,若是類是封裝的
    //則須要將⽅法聲明爲private和non-virtual
    proteted virtual void OnNewMail(NewMailEventArgs e) 
    { 
      //出於線程安全考慮,將委託字段保存到⼀個臨時字段中
      EventHadler<NewMailEventArgs> temp = m_NewMail; 
      if(temp!=null){temp(this,e);} 
     } 
 
    //將輸⼊轉化爲但願的事件
    public void SimulateNewMail(String from,String to,String subject) 
     {
         //構建⼀個對象存放給事件接收者的信息
        NewMailEventArgs e = new NewMailEventArgs(from,to,subject);  
        //引起 
        OnNewMail(e);  
      }
}
 
委託與事件
關鍵字「event」是個修飾詞,在絕⼤多數的情形中,被指定爲委託(delegate)的對象和被指定爲事件(event)的對象是能夠互換的。然⽽,事件還有特殊之處:
 ● 事件就像⼀個委託類型的字段。該字段引⽤了⼀個表明事件處理器的委託,這些處理器是被添加到事件上的;
 ● 事件只能在聲明它的類中被調⽤,⽽全部能見到委託的地⽅均可以使⽤委託;
 ● 事件能夠被包含在接口中⽽委託不能夠;
 ● 事件有可被重寫的Add和Remove存取(acccessor)⽅法;
 

(九)、Linq表達式、異步處理

LINQ
語言集成查詢 (LINQ) 是一系列直接將查詢功能集成到 C# 語言的技術統稱,好比涵蓋:SQL 數據庫查詢、XML 文檔查詢、List對象查詢、Array對象查詢、String對象查詢……。 藉助 LINQ,查詢成爲了最高級的語言構造,就像類、方法和事件同樣。
 
示例:
class LINQQueryExpressions
{
    static void Main()
    {
        
        // Specify the data source.
        int[] scores = new int[] { 97, 92, 81, 60 };
 
        // Define the query expression.
        IEnumerable<int> scoreQuery =
            from score in scores
            where score > 80
            select score;
 
        // Execute the query.
        foreach (int i in scoreQuery)
        {
            Console.Write(i + " ");
        }            
    }
}
// Output: 97 92 81
 
更詳細的Linq用法請參考:
 
異步處理
異步是 .NET 中充分使用處理器核心資源的機制,異步機制直接處理多個核心上的阻塞 I/O 和併發操做以提升系統執行效率。
.NET 異步的特色:
一、等待 I/O 請求返回的同時,可經過生成處理更多請求的線程,處理更多的服務器請求。
二、等待 I/O 請求的同時生成 UI 交互線程,並經過將長時間運行的工做轉換到其餘 CPU 核心,讓 UI 的響應速度更快。
 
使用基於 .NET 任務的異步模型可直接編寫綁定 I/O 和 CPU 的異步代碼。 該模型由 Task 和 Task<T> 類型以及 C# 和 Visual Basic 中的 async 和 await 關鍵字公開。 (有關特定語言的資源,請參見另請參閱部分。)
 
Task是用於實現稱之爲併發 Promise 模型的構造。 簡單地說,它們「承諾」,會在稍後完成工做。
Task 表示不返回值的單個操做。
Task<T> 表示返回 T 類型的值的單個操做。
 
Task在當前線程上執行,且在適當時會將工做委託給操做系統。 可選擇性地經過 Task.Run API 顯式請求任務在獨立線程上運行。
 
示例:
//定義一個基於Task的異步方法
public Task<string> GetHtmlAsync()
{
    // Execution is synchronous here
    var client = new HttpClient();
    return client.GetStringAsync("https://www.dotnetfoundation.org");
}
 
//第二個異步方法
public async Task<string> GetFirstCharactersCountAsync(string url, int count)
{
    // Execution is synchronous here
    var client = new HttpClient();
 
    // Execution of GetFirstCharactersCountAsync() is yielded to the caller here
    // GetStringAsync returns a Task<string>, which is *awaited*
    var page = await client.GetStringAsync(url);
 
    // Execution resumes when the client.GetStringAsync task completes,
    // becoming synchronous again.
 
    if (count > page.Length)
    {
        return page;
    }
    else
    {
        return page.Substring(0, count);
    }
}
 
//調用示例
var str = await GetHtmlAsync();
var str2 = await GetFirstCharactersCountAsync("https://www.dotnetfoundation.org",100);
 
更深刻地瞭解 .NET 上的異步編程
 

3、.NET 上的 Web 開發: ASP.NET Core

.NET上的Web解決方案由ASP.NET Core 框架實現,某種程度上你能夠將之理解爲Java界的Spring MVC。ASP.NET 是經典.NET上的Web解決方案,咱們建議新的Web應用應該選擇ASP.NET Core。
當前Web開發存在兩種主要的風格:MVC,Web API。MVC指的是模型--視圖--控制器的Web程序設計模式,而Web API指的是面向RESTful API場景的Web程序設計模式,它僅提供API調用的響應而不關心視圖。
 
ASP.NET Core
ASP.NET Core MVC 框架由以下基本組件構成:
路由
模型綁定
模型驗證
依賴關係注入
篩選器
區域
Web API
Razor 視圖引擎
強類型視圖
標記幫助程序
視圖組件
 
控制器:ASP.NET Core MVC 的Web請求入口是由Controller類型或其子類型的公共方法實現的,通常狀況下每一個請求入口都是一部分業務邏輯代碼的聚合。
 
例:
public class DefaultController : ControllerBase
{
    public ActionResult<string> Index()
    {
        return "hello,world";
    }
}
 
路由:ASP.NET Core MVC 創建在 ASP.NET CORE 的路由之上,是一個功能強大的 URL 映射組件,可用於生成具備易於理解和可搜索 URL 的應用程序。 它可以讓你定義適用於搜索引擎優化 (SEO) 和連接生成的應用程序 URL 命名模式,而不考慮如何組織 Web 服務器上的文件。 可使用支持路由值約束、默認值和可選值的方便路由模板語法來定義路由。
 
例:
routes.MapRoute(name: "Default", template: "{controller=Home}/{action=Index}/{id?}");
 
模型:ASP.NET Core MVC 模型綁定將客戶端請求數據(窗體值、路由數據、查詢字符串參數、HTTP 頭)轉換到控制器能夠處理的對象中。 所以,控制器邏輯沒必要找出傳入的請求數據;它只需具有做爲其操做方法的參數的數據。
 
例:
public async Task<IActionResult> Login(LoginViewModel model, string returnUrl = null) { ... }
 
模型驗證:ASP.NET Core MVC  經過使用數據註釋驗證屬性修飾模型對象來支持驗證。 驗證屬性在值發佈到服務器前在客戶端上進行檢查,並在調用控制器操做前在服務器上進行檢查。
 
例:
using System.ComponentModel.DataAnnotations;
public class LoginViewModel
{
    [Required]
    [EmailAddress]
    public string Email { get; set; }
 
    [Required]
    [DataType(DataType.Password)]
    public string Password { get; set; }
 
    [Display(Name = "Remember me?")]
    public bool RememberMe { get; set; }
}
 
Razor視圖引擎: Razor 是一種緊湊、富有表現力且流暢的模板標記語言,用於使用嵌入式 C# 代碼定義視圖。 Razor 用於在服務器上動態生成 Web 內容。 能夠徹底混合服務器代碼與客戶端內容和代碼。咱們能夠在MVC工程中,往Controller添加請求入口的View文件,這些View文件表明視圖文件(.cshtml),這些文件默認使用Razor視圖引擎來實現服務端渲染視圖。
例:
Index.cshtml:
 
<!-- 單行代碼塊 -->
@{ var myMessage = "Hello World"; }
 
<!-- 行內表達式或變量 -->
<p>The value of myMessage is: @myMessage</p>
 
<!-- 多行代碼塊 -->
@{
var greeting = "Welcome to our site!";
var weekDay = DateTime.Now.DayOfWeek;
var greetingMessage = greeting + " Today is: " + weekDay;
}
<p>The greeting is: @greetingMessage</p>
 
 
Web API:  ASP.NET Core 支持使用 C# 建立 RESTful 服務,也稱爲 Web API。 Web API 使用控制器響應這些請求,Web API 中的控制器是派生自 ControllerBase 的類。
 
例:
[Route("api/[controller]")]
[ApiController]
public class ValuesController : ControllerBase
{
    public ActionResult<Pet> Create(Pet pet)
    {
        pet.Id = _petsInMemoryStore.Any() ? _petsInMemoryStore.Max(p => p.Id) + 1 : 1;
        _petsInMemoryStore.Add(pet);
 
        return CreatedAtAction(nameof(GetById),
        new { id = pet.Id }, pet);
    }
}
 
SignalR: ASP.NET Core SignalR 是一個開源代碼庫,它簡化了嚮應用添加實時 Web 功能的過程。 實時 Web 功能使服務器端代碼可以即時將內容推送到客戶端。
SignalR 的適用對象:須要來自服務器的高頻率更新的應用。
 
例如:
遊戲、社交網絡、投票、拍賣、地圖和 GPS 應用;
儀表板和監視應用;
協做應用,例如白板應用和團隊會議軟件;
須要通知的應用, 社交網絡、電子郵件、聊天、遊戲、行程警示以及許多其餘應用都使用通知;
 
SignalR 提供了一個用於建立服務器到客戶端遠程過程調用(RPC)的 API。 RPC 經過服務器端 .NET Core 代碼調用客戶端上的 JavaScript 函數。
如下是 ASP.NET Core SignalR 的一些功能:
一、自動管理鏈接。
二、向全部鏈接的客戶端廣播消息。 例如,聊天室。
三、將消息發送到特定的客戶端或客戶端組。
四、擴展以處理增長的流量。
 

 4、.NET 上的ORM

EF6 & EF Core
EntityFramework 6.x (EF6) 是經典 .NET上的 ORM 框架,它功能全面在Windows上運行穩定。
EntityFramework Core (EF Core) 是 EntityFramework 的跨平臺移植版本,目前功能上與 EF6 仍有差距,能夠知足絕大部分 CRUD 操做。
下圖是 EF6 與 EF Core 在數據庫支持上的對比: 
 
其它ORM
dapper 是Stack Overflow貢獻的輕量級 ORM 框架,兼容.NET Core 和 .NET 4.5x,它直接擴展了.NET Connection 對象。
SmartSql 是一個包括ORM及延伸功能的數據、緩存讀寫與配置框架。
 
以上介紹的主要的ORM工具均可以在Github上找到其官方主頁。
 

5、.NET 微服務和容器化

.NET Core 是最先響應微服務與容器化部署的技術平臺。.NET 團隊在Docker Hub 官網上維護着全部主要的 .NET Core 版本的 Docker 鏡像。
你能夠在這個連接上找到這些鏡像: https://hub.docker.com/_/microsoft-dotnet-core
 
值得一提的是,.NET Core 在 Docker 上的性能表現超過了大部分其餘同類技術平臺。例如使用 Raygun 工具測試相同 Linux 環境的上運行的 Node.js 與 .NET Core 的性能對比,.NET Core 的性能是 Node.js 的2000%。
 
.NET Core 是天生爲雲計算優化的技術平臺,有着優良的可伸縮性,併兼容主流的雲計算平臺,好比 Azure、AWS、阿里雲。
 

上圖是 .NET Core 上實現的微服務與 docker 容器部署的典型架構示例github

 
關於如何設計、發佈 .NET Core 的微服務到 Docker 鏡像,能夠下載這個官方中文說明書: https://dotnet.microsoft.com/download/thank-you/microservices-architecture-ebook-zh-cn

6、.NET平臺與Java平臺的互換性

  .NET Java    

包管理web

nuget Maven
Web場景開發
ASP.NET
ASP.NET Core
Spring Boot
ORM
EntityFramework 6.x
EntityFramework Core
dapper
NHibernate
SmartSql
Hibernate
Mybatis
 
單元測試
MSUnit
XUnit.net
JUnit
Android/ios 開發 Xamarin
Android SDK
RoboVM
Windows 開發
.NET Framework 4.x
.NET Core 3.0+
Mono
Oracle JDK
Open JDK (free)
Mac OS 開發
Mono
Xamarin/.NET Core
Oracle JDK
Open JDK(free)
linux開發
Mono
.NET Core
Oracle JDK
Open JDK(free)
docker支持
.NET Core
ASP.NET Core
Mono
Oracle JDK
Open JDK(free)
AI/數據分析
ML.net
ONNX Runtime
Microsoft Cognitive Toolkit(CNTK)
tensorflow.net
.NET for Apache Spark
Eclipse Deeplearning4j
Apache OpenNLP
Java-ML
Spark
Flink
Kafka
Storm
遊戲開發
Unity (C#語言)
MonoGame
CRYENGINE
 
IoT .NET Core Open IoT Stack for Java

 

以上關於 .NET 平臺及 Java 平臺的比較信息來源於一小部分有表明性的技術棧,僅供參考。
關於 .NET 平臺更多的生態內容能夠參考這個連接: https://github.com/thangchung/awesome-dotnet-core
 
感謝 .NET 社羣中的朋友幫忙審校。
 
參考連接:
相關文章
相關標籤/搜索