C#與C++的發展歷程第二 - C#4.0再接再礪

系列文章目錄html

1. C#與C++的發展歷程第一 - 由C#3.0起程序員

2. C#與C++的發展歷程第二 - C#4.0再接再礪編程

 

開始本系列的第二篇,這篇文章中將介紹C#4.0中一些變化,如C++有相似功能也將一併介紹。我的感受C#4.0中增長的語言方面的特性不是不少,多是這個時期都在着力完成隨之發佈的新的4.0版的CLR。整體來講C#4.0中有4個方面的特性。下面依次介紹:json

 

C#4.0 (.NET Framework 4.0, CLR 4.0)c#

 

C# 動態類型

在諸如Javascript這樣的腳本語言中咱們能夠隨時給對象添加成員 :數組

1
2
3
4
5
6
7
8
9
10
11
var  student = {};
student.Name=  '張三' ;
student.StudyDay=110;
student.PlayDay=50;
student.CalcMark =  function (talent)
{
     var  study = Math.pow(1.01,student.StudyDay)/4.9*100;
     var  play=Math.pow(0.99,student.PlayDay)/4.9*100;
     var  talentmark=student.PlayDay/160*100;
     return  talent?study+talentmark:study+play;
};

如今C#中經過動態類型的支持,咱們也能編寫相似的代碼。以下:安全

1
2
3
4
5
6
7
8
9
10
dynamic student =  new  ExpandoObject();
student.Name =  "李四" ;
student.StudyDay = 120;
student.PlayDay=40;
student.CalcMark = (Func< bool , double >)(talent=>{
              var  study=Math.Pow(1.01,student.StudyDay)/4.9*100;
              var  play=Math.Pow(0.99,student.PlayDay)/4.9*100;
              var  talentMark=student.PlayDay/160*100;
              return  talent?study+talentMark:study+play;
              });

調用動態添加和方法和調用普通方法同樣。併發

1
var  mark = student.CalcMark( false );

給動態類型添加事件也是能夠的,如:app

1
2
3
student.MakeMistakes =  null ;
student.MakeMistakes +=  new  EventHandler((sender, e)=>
                         Console.WriteLine( "{0}被請家長。" , ((dynamic)sender).Name));

觸發事件看起來和調用函數差很少:框架

1
student.MakeMistakes(student, new  EventArgs());

這種動態類型的一個很大做用就是在咱們想傳遞一個對象但不想爲此定義一個類時採用。如ASP.NET MVC 3起ControllerBase類新增的的ViewBag屬性就是dynamic對象適用場景的典型例子。

1
public  dynamic ViewBag {  get ; }

有了ViewBag能夠靈活的在Controller和View之間傳遞數據,而不要事先定義Model。固然使用ViewBag的效率也不如強類型的Model類。

咱們能夠定義一個返回dynamic對象的方法:

1
2
3
4
5
6
public  dynamic GetStudent()
{
     dynamic student =  new  ExpandoObject();
     //略去添加成員的代碼..
     return  student;
}

調用這個方法咱們能夠獲得一個動態對象,並訪問其中定義的值:

1
dynamic student = GetStudent();

一樣咱們也能夠定義一個接受dynamic對象的函數:

1
2
3
4
public  void  GetMark(dynamic student)
{
     double  mark = student.CalcMark( false );
}

使用這種接收或返回動態類型的函數要很是當心,每每錯誤到了運行時纔會出現。

這裏dynamic聲明的對象是一類實現了IDynamicMetaObjectProvider接口類型的對象(也必須如此),這個接口提供的功能能夠歸納爲"延遲綁定",即在運行時才肯定類型。IDynamicMetaObjectProvider類型的對象執行在DLR上完成。

DLR是CLR4.0開始新增的專門處理動態類型的部分,全稱Dynamic Language Runtime。經過DLR對動態類型的支持,能夠在支持 DLR 互操做性模型的各類語言(如IronPython)之間共享 IDynamicMetaObjectProvider接口對象的實例。如咱們用C#實例化一個DynamicObject實例,並傳遞給IronPython函數。 

上文中介紹的ExpandoObject是一個IDynamicMetaObjectProvider接口的簡單實現,其提供了基本的在運行時添加和刪除實例的成員以及設置和獲取這些成員的值的功能。

ExpandoObject 類還實現 IDictionary<String, Object> 接口,使用這個接口的方法能夠在運行時判斷某個動態成員是否存在。下面的例子來自MSDN:

示例代碼中將 ExpandoObject 類的實例強制轉換爲 IDictionary<TKey, TValue> 接口,並枚舉該實例的成員。

1
2
3
4
5
6
7
8
dynamic employee =  new  ExpandoObject();
employee.Name =  "John Smith" ;
employee.Age = 33;
 
foreach  ( var  property  in  (IDictionary<String, Object>)employee)
{
     Console.WriteLine(property.Key +  ": "  + property.Value);
}

經過將 ExpandoObject 實例強制轉換到 IDictionary<String, Object> 接口,還能夠經過IDictionary接口以刪除鍵值對的方式來刪除動態成員。 以下例子:

1
2
3
dynamic employee =  new  ExpandoObject();
employee.Name =  "John Smith" ;
((IDictionary<String, Object>)employee).Remove( "Name" );

ExpandoObject類還實現了INotifyPropertyChanged 接口,在成員添加、刪除或修改時會引起 PropertyChanged 事件。在一些使用MVVM模式的環境中,以ExpandoObject做爲ViewModel對象可以方面的通知View層其內容更改以實現數據綁定。

 

使用動態對象的代碼在第一次給動態對象賦值後,在運行時賦值代碼執行完成後,動態類型也就肯定了。後續使用就應該注意類型要匹配。以下面的代碼在運行時就會因爲類型不匹配而出現異常。

1
2
dynamic year=  "2014" ;
year++;

從新給動態對象賦值能夠改變其運行時的類型,下面的代碼在運行時不會報錯:

1
2
3
dynamic year=  "2014" ;
year = 2014;
year++;

 

若是須要更復雜的運行時動態行爲,可使用DynamicObject對象,可是須要注意不能直接實例化DynamicObject類型的對象,須要繼承DynamicObject類型建立本身的對象,而後再實例化這個自定義DynamicObject類型的對象。DynamicObject類預約義一些高級的延遲綁定功能,經過實現它能夠很輕鬆的建立本身的動態類型,從而自定義能夠在動態對象上執行哪些操做以及如何執行這些操做。下面一樣是一個來自MSDN的例子。

示例代碼實現的類繼承了DynamicObject類,並給出了新的實現,其將動態類的屬性保存在一個內部字典中,並提供了查詢動態設置的屬性數量的Count屬性。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
// DynamicDictionary繼承自DynamicObject
public  class  DynamicDictionary : DynamicObject
{
     //內部字典對象
     Dictionary< string object > dictionary =  new  Dictionary< string object >();
      
     //返回動態添加的屬性的數量,即內部字典元素的個數
     public  int  Count
     {
         get
         {
         return  dictionary.Count;
         }
     }
      
     //當試圖獲取一個不是定義於類的屬性的值時,將調用這個方法
     public  override  bool  TryGetMember(GetMemberBinder binder,  out  object  result)
     {
         //將屬性名變爲小寫,實現屬性名大小寫無關
         string  name = binder.Name.ToLower();
          
         //若是在字典中找到訪問的屬性名,將屬性值經過result返回,並返回true,反之返回false
         return  dictionary.TryGetValue(name,  out  result);
     }
      
     //當試圖設置一個不是定義於類的屬性的值時,將調用這個方法
     public  override  bool  TrySetMember(SetMemberBinder binder,  object  value)
     {
         //將屬性名變爲小寫,實現屬性名大小寫無關
         dictionary[binder.Name.ToLower()] = value;
          
         //任什麼時候候均可以添加新的屬性,方法老是返回true
         return  true ;
     }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class  Program
{
     static  void  Main( string [] args)
     {
         //實例化一個自定義動態類對象
         dynamic person =  new  DynamicDictionary();
          
         //添加動態屬性(TrySetMember方法被調用)
         person.FirstName =  "Ellen" ;
         person.LastName =  "Adams" ;
          
         //獲取動態屬性的值(TryGetMember方法被調用)
         //屬性名大小寫無關
         Console.WriteLine(person.firstname +  " "  + person.lastname);
          
         //獲取Count屬性的值(沒有調用TryGetMember方法,Count屬性是定義於類中的)
         Console.WriteLine( "動態屬性的數量爲:"  + person.Count);
          
         //下面的語句會在運行時拋出異常
         //因爲不存在"address"屬性,TryGetMember方法返回false,從而致使RuntimeBinderException
         Console.WriteLine(person.address);
     }
}

 

更多關於實現DynamicObject類型的討論,能夠見園友JustRun的這篇文章

其中實現了一個DynamicJson類,能夠將json字符串轉爲一個能夠像Javascript中同樣使用的json動態對象。

若是DynamicObject也沒法實現某些須要的功能,能夠直接實現IDynamicMetaObjectProvider接口來控制動態類型對象的延遲綁定行爲。

 

最後來看下動態類型的一些其它做用。經過動態類型的支持,咱們能夠把以前一些須要反射來實現的功能交由動態類型來實現。一樣是以前使用的Student類做爲例子:

先定義一個Student類:

1
2
3
4
5
6
7
8
9
10
11
12
13
public  class  Student
{
     public  string  Name {  get set ; }
     public  int  StudyDay {  get set ; }
     public  int  PlayDay {  get set ; }
     public  double  CalcMark( bool  talent)
     {
         var  study = Math.Pow(1.01, StudyDay) / 4.9 * 100;
         var  play = Math.Pow(0.99, PlayDay) / 4.9 * 100;
         var  talentMark = PlayDay / 160 * 100;
         return  talent ? study + talentMark : study + play;
     }
}

假如這個Student類位於一個沒有在當前程序編譯時引用的程序集中,即你須要動態加載一個程序集並經過反射實例化Student類型,設置其屬性並調用方法:

1
2
3
4
5
6
7
8
9
Assembly myAssembly = Assembly.LoadFrom( "StudentAssembly.dll" );
Type studentType = myAssembly.GetType( "Student" );
object  student = Activator.CreateInstance(studentType);
  
studentType.GetProperty( "Name" ).SetValue(student,  "王五" null );
studentType.GetProperty( "StudyDay" ).SetValue(student, 120,  null );
studentType.GetProperty( "PlayDay" ).SetValue(student, 30,  null );
object  markobj = studentType.GetMethod( "CalcMark" ).Invoke(student,  new  object [] {  false  });
double  mark = Convert.ToDouble(markobj);

如今用了動態類型的支持,咱們能夠編寫下面這樣賞心悅目的代碼:

1
2
3
4
5
6
dynamic student = Activator.CreateInstance(studentType);
  
student.Name = "趙六" ;
student.StudyDay = 120;
student.PlayDay = 30;
double  mark = student.CalcMark( false );

 

.NET社區的開源項目Clay將.NET的動態特性發揮到極致,使用Clay能夠徹底擺脫C#的類型限制。關於Clay再次推薦JustRun的一篇文章

C++方面沒有相似特性,沒的寫。

 

C# 可選參數與命名參數

可選參數

可選參數這個特性提及來很簡單, 來看一個帶有可選參數方法的聲明:

1
2
3
4
public  void  Log( string  log, LogLevel level = LogLevel.Alarm ,LogTo destination = LogTo.Database)
{
     //...
}

調用這個函數有三種方式:

1
2
3
Log( "hello world" );
Log( "hello world"  , LogLevel.Info);
Log( "hello world"  , LogLevel.Info, LogTo.File);

須要注意的是可選參數必須定義在全部非可選參數的後面。這個特性的加入使之前不少須要定義重載函數的場景能夠用一個支持可選參數的函數代替。

若是有一個函數重載和帶可選參數方法的一種調用方式相同,則會優先調用沒有可選參數的重載。即若是有下面的函數重載:

1
2
3
4
public  void  Log( string  log, LogLevel level)
{
     //...
}

則對於上文中第二種調用方式會優先選擇這個重載。

關於可選參數的實現內幕能夠看Artech大神的這篇文章

命名參數

命名參數功能可讓咱們在傳入實參時,在前面加上形參的名字,用以標識實參對應那個形參。

對於上面方法的調用能夠這樣:

1
Log( "hello world" , level: LogLevel.Info, destination:LogTo.File);

使用命名參數時,能夠改變實參傳入的順序:

1
Log( "hello world" , destination:LogTo.File, level: LogLevel.Info);

這樣的調用效果和以前是同樣的。

和可選參數定義相似的是,命名參數必須放在調用參數列表的最後。

 

C++既沒有可選參數也不支持命名參數,C++11對參數的改進就是在原來可變參數的基礎上增長了可變參數模板。這實際上是很強大的一個功能,讓變長的參數也能夠強類型化。這個特性留到後面的文章再說。

 

C# 改進的COM交互

C#中COM互操做的改進徹底是得益於前兩條新特性的加入。固然這塊也是博主最不熟悉的領域,以前從沒寫過和COM交互的代碼。因此仍是從國外程序員的博客上借(piao)用(qie)一個例子(出處)吧。

在C#4以前調用COM的代碼經常會出現不少ref參數等。

1
2
3
4
5
6
static  void  Main()
{
     Word.Application app =  new  Word.Application();    
     object  m = Type.Missing;
     app.Documents.Add( ref  m,  ref  m,  ref  m,  ref  m);
}

C#4.0出現使這些都方便了不少:

1
2
Word.Application app =  new  Word.Application();
app.Documents.Add();

就是這樣簡單、任性!

另外結合動態類型,一些返回值的獲取、參數傳遞以及賦值也大大簡化了。

關於COM交互的支持在未來可能就真沒什麼用了,如今COM已經完美轉型爲WinRT,WinRT平臺上微軟給各類語言的交互提供了很完美的支持。聽說是性能不太好,但代碼顏值很高

 

這條目就更沒C++什麼事了。

 

C# 逆變與協變

C#4.0和.NET Framework 4.0開始支持的一個很重要的特性就是逆變與協變。爲此C#引入了2個新的關鍵字in和out,分別表示逆變和協變。那什麼是逆變和協變呢。仍是以例子開始說明,如今有兩個擁有繼承關係的類型:

爲何關鍵字是in和out呢,能夠這樣理解,in表示泛型的參數被傳入一個更小的做用域內,而這個範圍內的方法知道如何去處理一個更具體的類型,這樣操做是安全的。out表示泛型的參數會被返回到一個更大的做用域,因爲自己就能夠用父類去調用一個子類中從父類繼承的屬性或方法因此這種操做也是安全的。

1
2
3
4
5
6
7
8
9
10
11
public  class  Panda : Animal
{
     public  string  NickName {  get set ; }
}
 
public  class  Animal
{
     public  string  Name {  get set ; } 
     
     public  int  Age {  get set ; }
}

在這以前的.NET版本中,下面的代碼是沒法被支持的,由於Animal和Panda是不一樣的類型:

1
2
var  pandas =  new  List<Panda>();
IEnumerable<Animal> animals = pandas;

在C#4.0和.NET Framework 4.0以後這樣代碼能夠順利被執行,緣由就是協變的支持,來看一下.NET 4.0中IEnumerable接口的定義:

1
public  interface  IEnumerable< out  T> : IEnumerable

能夠看到在泛型類型以前多了表示協變的out關鍵字,咱們來給協變一個具體的定義,經過定義你們就能夠了解爲啥上面的賦值能夠成立了。

協變:協變容許與泛型類型參數所定義的類型相比,派生程度更大的類型。相反,逆變就是容許與泛型形參所指定的實參類型相比,派生程度更小的實參類型。

.NET中支持逆變與協變的主要有如下幾個地方:部分接口,委託還有數組。下表整理了下這些支持逆變或協變的類型(自行經過in仍是out判斷是逆變仍是協變),主要參考的MSDN文檔,可能有不全,歡迎補充:

分類 類名

接口

主要是集合接口和比較接口

IEnumerable<out T>
IEnumerator<out T>
IQueryable<out T>
IGrouping<out TKey, out TElement>
IComparer<in T>
IEqualityComparer<in T>
IComparable<in T>
 

Action<in T>

Action<in T1, in T2>

... ...

委託

Func<out TResult>

Func<in T, out TResult>

Func<in T1, in T2, out TResult>

... ...

Predicate<in T>
Comparison<in T>
Converter<in TInput, out TOutput>

前面的例子展現了協變,再來看一個逆變的例子,如今咱們把Animal改爲支持比較的,比較的是兩隻動物年齡的大小:

1
2
3
4
5
6
7
8
9
10
11
12
public  class  Animal: IComparable<Animal>
{
     public  string  Name {  get set ; }
 
     public  int  Age {  get set ; }
 
     public  int  CompareTo(Animal other)
     {
         if  (other ==  null return  1;
         return  Age.CompareTo(other.Age);
     }
}

基於IComparable<T>逆變的支持,下面的代碼能夠正常工做:

1
2
3
4
5
6
var  pandas =  new  List<Panda>()
{
      new  Panda() {NickName =  "HuanHuan"  ,Age = 12 },
      new  Panda() {NickName =  "LeLe" , Age = 11 }
};
var  pandaSmallToBig = pandas.OrderBy(p=>p).ToList();

在排序後的列表中,LeLe在HuanHuan前面。

看過接口對協變和逆變的支持,再來看一些委託中的逆變與協變,因爲如今基本上能夠用Action和Func表示一切委託,因此示例也以它們爲表明:

1
2
3
4
5
6
//逆變
Action<Animal> animalAction = ani => ani.Age = 15;
Action<Panda> pandaAction = animalAction;
//協變
Func<Panda> pandaFunc = () =>  new  Panda() { NickName =  "HuanHuan" , Age = 12 };
Func<Animal> animalFunc = pandaFunc;

相信經過這四行代碼足矣瞭解委託中的協變和逆變。

最後數組的逆變也能夠用一行代碼來歸納:

1
2
var  pandas =  new  List<Panda>();
Animal[] animal = pandas.ToArray();

這行代碼會致使Resharper給出一個警告,說可能會由於協變出現運行時異常。

 

上面所介紹的都是.NET中一些內置類型對逆變和協變的支持。在咱們本身的接口中也能夠支持逆變或協變。

先來看看協變的使用,以代碼爲例,能夠應用協變的場景有以下兩種,注意代碼註釋:

1
2
3
4
5
6
7
8
9
10
//1.泛型類型做爲返回值類型
interface  ICovariant< out  R>
{
     R GetSomething();
}
//2.做爲委託類型參數的泛型類型
interface  ICovariant< out  R>
{    
     void  DoSomething(Action<R> callback);
}

對於逆變通常只用於內部函數的參數類型:

1
2
3
4
interface  IContravariant< in  A>
{    
     void  SetSomething(A sampleArg);
}

逆變和協變能夠混合使用,但也要各自遵循上面的規則。

另一個值得一提的,協變或逆變都布不能「繼承」,以協變爲例來講明:

1
2
interface  ICovariant< out  T> { }
interface  IDerived<T> : ICovariant<T> { }

IDerived<T>不具有協變特性,若是須要協變,須要顯示指定:

1
interface  IDerived< out  T> : ICovariant<T> { }

注意這裏IDerived也只能是協變,指定逆變是不行的。

1
2
//下面代碼沒法編譯
//interface IDerived<in T> : ICovariant<T> { }

 

最後特別注意,逆變和協變只針對引用類型有效,值類型沒法進行逆變和協變。標記爲逆變或協變的泛型類型也不能用做ref或out參數。不能給協變的泛型類型添加泛型約束,可是能夠給逆變的泛型參數在泛型方法中添加泛型約束。

 

.NET Framework 4.0 Tuple類型

.NET 4.0中新增的Tuple這個類型頗有用,固然這個類使用很簡單,因此也很容易介紹。一句話歸納Tuple的做用就是把不一樣類型的對象組合在一塊兒。Tuple類有九個兄弟,最多的有8個泛型參數。

建立一個Tuple對象有兩種方法,第一使用構造函數,如:

1
var  student =  new  Tuple< int , string int int >(3,  "小明" , 12, 95);

或者可使用Tuple非泛型類上的Create方法:

1
var  student = Tuple.Create(3,  "小明" , 12, 95);

第二種方法能夠省略泛型類型,Create泛型方法的泛型類型會自動推斷。

有了Tuple對象以後,能夠經過Item1,Item2這樣的屬性依次訪問存入Tuple的值,注意這些屬性都是隻讀的。

在博主接觸的場景中,Tuple的做用主要有二。

其一,用作返回多個對象的函數的返回類型。在Tuple出現以前,若是一個函數須要返回多個值/對象,只能經過ref或out參數這種方式。而有了Tuple,能夠把要返回的對象保證在Tuple中。這個很簡單就不給代碼示例了。

其二,使用Dictionary<K,V>時,有時候V是一個包含多個對象的對象。如今除了用一個類來封裝全部屬性以外,對於很簡單的狀況,能夠直接放在Tuple中做爲字典值。

總之,有了Tuple,代碼的可讀性會大大提升。

 

C++11 STL std::tuple類型

不知道是否是跟C#學的,在C++11標準下的STL也增長了tuple類型。這是一個模板類型,其對象的建立和成員的訪問都與.NET Framework中的Tuple很是相似。

不一樣的是藉助C++11新增的可變參數模板特性,C++11STL中的tuple能夠接受任意多了個類型參數,而不像.NET Framework中的Tuple僅有九種不一樣的實現,一次性接受的參數個數有限。這也再次體現了C++的模板功能方面的強大。

C++11 STL中的tuple的定義和初始化方式以下:

定義,須要在模板中指明成員的類型,以下(使用C#中的場景):

1
std::tuple< int , std::string,  int int > student;

若是在聲明時直接初始化,必須使用直接初始化語法(tuple的構造函數爲explicit,因爲拷貝初始化方式隱式使用構造函數,因此沒法進行拷貝初始化):

1
2
3
std::tuple< int , std::string,  int int > student(3,  "小明" , 12, 95); //正確,顯示調用構造函數
std::tuple< int , std::string,  int int > student{3,  "小明" , 12, 95}; //正確,使用直接初始化
//std::tuple<int, std::string, int, int> student = {3, "小明", 12, 95};//錯誤,不能使用拷貝初始化方式

STL中也提供了make_tuple函數來構造一個tuple對象,這點與.NET中Tuple的Create方法很想,經過make_tuple,能夠不用去寫那一串模板類型:

1
auto  student = make_tuple(3,  "小明" , 12, 95);

STL也提供了一個模板函數get用於訪問tuple中的成員,模板參數用於傳入要訪問第幾個成員:

1
2
3
auto  no = get<0>(student);
auto  name = get<1>(student);
auto  age = get<2>(student);

STL的中的tuple重寫了<以及==等運算符,因此能夠方便比較兩個tuple對象。

一樣,在C++中tuple類型最重要的一個做用也是在函數中使用tuple一次返回多個值。這個使用上也很簡單也沒有什麼特殊之處,篇幅緣由就不給出例子了。

 

.NET Framework 4.0 並行LINQ

並行LINQ來自於.NET Framework 4.0新增的TPL(Task Parallel Library,即任務並行庫)。TPL帶來了.NET 4中對並行和異步兩部分的新特性,其覆蓋範圍至關普遍,異步部分在C#5.0又有了大改變將在下一篇文章中重點介紹,並行部分這小節只討論PLINQ,其餘話題很少介紹,園子裏也相關文章太多太多。有興趣的同窗能夠分別去了解異步和並行兩方面TPL的新特性。奉上一張有關.NET對異步併發編程的支持的思惟導圖。園友們能夠參考其中的分支對不瞭解的區域重點學習。

圖1 .NET中的併發/異步編程

本節介紹其中的並行LINQ主要是考慮到前文介紹過LINQ,爲了保證完整性,這裏把並行LINQ也提一下。

PLINQ主要是使以前順序執行的LINQ查詢能夠以並行方式來執行,從而充分利用多核CPU的計算能力。

這裏一樣準備一個圖片幫助你們理解下PLINQ的相關方法的做用,能夠將其做爲一個綱要來學習其中的相關細節。

圖2

一圖勝千言,下面對照上面的圖來大概介紹下PLINQ的某些方面。PLINQ最爲.NET中最容易使用的一種並行編程技術,其「入口」只有一個AsParallel()方法。經過這個方法能夠將一個普通的LINQ查詢轉爲並行LINQ即PLINQ查詢(若是經執行環境評估後面的查詢不能並行執行,則依然會順序執行)。這樣LINQ的查詢操做將會並行執行。除了並行執行,PLINQ支持幾乎所有的LINQ查詢如Select()、Where()以及那些聚合操做如Average()和Sum()等。與AsParallel()相對還能夠經過AsSequence()方法將一個PLINQ轉回LINQ即中止後續查詢的並行執行。

PLINQ查詢默認不保持原集合中元素的順序,若是想讓獲得的結果保持原順序,請在AsParallel()後使用AsOrdered()而後再編寫查詢操做。

對於PLINQ執行結果的使用,若是能夠並行使用就儘可能使用ForAll(),這樣效率最好,若是使用foreach等方式使用PLINQ的集合,集合將被處理爲一個序列。

在取消和異常處理方面,PLINQ使用CancellationToken和AggregateException,這與.NET環境中其餘並行和異步組件的模式是相同的,很容易使用。

具體使用代碼就再也不舉例了。此段內容僅做爲拋磚引玉。

 

預告

下篇文章將重點介紹C#5.0和.NET 4.5帶來的異步編程的巨大改進。同時也會附加介紹WinRT框架下使用C++和C#實現異步編程的方法。另外還有一些C#5.0其餘方面的小改進。

相關文章
相關標籤/搜索