C# 4.0中COM互操作性和方差得到增強(qiáng)
原創(chuàng)【51CTO獨(dú)家特稿】這里將為大家介紹C# 4.0當(dāng)中的COM互操作性以及方差這兩個(gè)新特性。51CTO之前曾報(bào)道過(guò)C#4.0新特性一覽及歷史回顧。
增強(qiáng)的COM互操作性特性
C# 4.0在COM互操作性支持方面提供了很多改進(jìn),使得你現(xiàn)在在.NET代碼中可以更容易地調(diào)用COM對(duì)象了,需要執(zhí)行的類型轉(zhuǎn)換更少了,ref關(guān)鍵字不再需要,也不再需要主互操作程序集或PIA,從本質(zhì)上講,C# 4.0提供了大量的新特性,特別是在COM互操作方面更是下足了功夫,在前一篇文章中談到的動(dòng)態(tài)查詢和命名/可選參數(shù)的支持,幫助提高了與COM API如Office自動(dòng)化API互操作的體驗(yàn)。
例如,下面是C# 4.0以前的版本打開(kāi)一個(gè)Word文件的代碼:
- using Word = Microsoft.Office.Interop.Word;
- namespace COMInterop
- {
- class Program
- {
- static void Main(string[] args)
- {
- Word.Application wordApplication =
- new Word.Application() { Visible = true };
- object missingValue = System.Reflection.Missing.Value;
- object readOnlyValue = true;
- object fileName = @"C:\\DevX.docx";
- wordApplication.Documents.Open(ref fileName, ref
- missingValue, ref readOnlyValue,
- ref missingValue, ref missingValue,
- ref missingValue, ref missingValue,
- ref missingValue, ref missingValue,
- ref missingValue, ref missingValue,
- ref missingValue, ref missingValue,
- ref missingValue,ref missingValue);
- }
- }
- }
在最后的open調(diào)用中,你可以看到需要傳遞大量的可選參數(shù)以滿足函數(shù)調(diào)用,隨著C# 4.0中可選和命名參數(shù)的引入,現(xiàn)在做同樣的事情,需要的代碼要少得多了。
下面是C# 4.0中用來(lái)打開(kāi)Word文檔的代碼:
- using Word = Microsoft.Office.Interop.Word;
- namespace COMInterop
- {
- class Program
- {
- static void Main(string[] args)
- {
- Word.Application wordApplication = new
- Word.Application() {Visible = true};
- wordApplication.Documents.Open(@"C:\\DevX.docx",
- ReadOnly: true);
- }
- }
- }
性能改善
PIA是由COM接口產(chǎn)生的,你可以在你的應(yīng)用程序代碼中使用這個(gè)程序集以一種強(qiáng)類型的方式與COM對(duì)象互操作,但它們很笨重,很消耗內(nèi)存,會(huì)顯著降低應(yīng)用程序的性能。相反,互操作程序集通過(guò)前面的代碼編譯生成,只包含你的應(yīng)用程序真正用到的互操作代碼,從而大大減少了程序集的大小,提高了應(yīng)用程序的性能。
動(dòng)態(tài)導(dǎo)入大多數(shù)COM函數(shù)都是接收并返回變量類型,在PIA中表示為對(duì)象,因此,當(dāng)你使用這些方法時(shí),需要使用適當(dāng)?shù)膹?qiáng)制類型轉(zhuǎn)換,但在C# 4.0中,你可以使用dynamic關(guān)鍵字代替COM函數(shù)中的object,因此,現(xiàn)在不必再進(jìn)行類型轉(zhuǎn)換了。
思考一下下面的代碼,你需要使用轉(zhuǎn)換在excel文檔中為某個(gè)特定單元格設(shè)置一個(gè)值:
- ((Excel.Range)excelObj.Cells[5, 5]).Value =
- "This is sample text";
上面的代碼需要使用強(qiáng)制類型轉(zhuǎn)換,但在C# 4.0中,你可以消除掉強(qiáng)制類型轉(zhuǎn)換了,這一切都得感謝dynamic關(guān)鍵字,下面是C# 4.0中的實(shí)現(xiàn)方法:
- excelObj.Cells[5, 5].Value = "This is sample text";
下面是一個(gè)更為完整的例子,使用的是C# 3.0代碼保存excel文檔:
- using Excel = Microsoft.Office.Interop.Excel;
- namespace COMInterop
- {
- class Program
- {
- static void Main(string[] args)
- {
- var excelApplication = new Excel.Application();
- excelApplication.Visible = true;
- dynamic excelWorkBook =
- excelApplication.Workbooks.Add(
- System.Reflection.Missing.Value);
- Excel.Worksheet wkSheetData = (
- Excel.Worksheet)excelWorkBook.ActiveSheet;
- excelWorkBook.SaveAs("Testfile.xls",
- System.Reflection.Missing.Value,
- System.Reflection.Missing.Value,
- System.Reflection.Missing.Value,
- System.Reflection.Missing.Value,
- System.Reflection.Missing.Value,
- Excel.XlSaveAsAccessMode.xlShared,
- System.Reflection.Missing.Value,
- System.Reflection.Missing.Value,
- System.Reflection.Missing.Value,
- System.Reflection.Missing.Value,
- System.Reflection.Missing.Value);
- }
- }
- }
在C# 4.0中,你不再需要使用缺失值和明確的強(qiáng)制類型轉(zhuǎn)換了,下面是在C# 4.0中沒(méi)有使用缺失值和強(qiáng)制類型轉(zhuǎn)換的代碼:
- using Excel = Microsoft.Office.Interop.Excel;
- namespace COMInterop
- {
- class Program
- {
- static void Main(string[] args)
- {
- var excelApplication = new Excel.Application();
- excelApplication.Visible = true;
- dynamic excelWorkBook = excelApplication.Workbooks.Add();
- Excel.Worksheet wkSheetData = excelWorkBook.ActiveSheet;
- excelWorkBook.SaveAs(
- "Testfile.xls",
- AccessMode: Excel.XlSaveAsAccessMode.xlShared);
- }
- }
- }
注意:COM有一個(gè)和托管代碼完全不同的編程模型,為了調(diào)用COM函數(shù),C#編譯器允許你傳遞參數(shù)值,并會(huì)產(chǎn)生臨時(shí)變量來(lái)保存這些值,當(dāng)函數(shù)調(diào)用完畢后這些變量就會(huì)被丟掉。
方差支持
在C# 4.0中,你可以對(duì)泛型類型指定in(僅輸入)好out(只返回)參數(shù),這些參數(shù)可以作為唯一的輸入?yún)?shù)或只作為這種類型的返回值被傳遞。
C# 4.0中對(duì)方差有兩方面的支持:協(xié)方差和方差。如果你必須使用完全匹配正式類型的名稱,那么返回的值或參數(shù)是不變的。如果你能夠使用更多的衍生類型作為正式參數(shù)類型的代替物,那么參數(shù)是可變的。如果你能夠?qū)⒎祷氐念愋头峙浣o擁有較少類型的變量,那么返回的值是逆變的。
我這里不涉及任何不變量參數(shù),你也應(yīng)該從C#早期版本中熟悉了。
協(xié)方差
使用一個(gè)簡(jiǎn)單的例子更容易理解協(xié)方差,注意string是一個(gè)特殊的類型,而object是一個(gè)泛型類型,因此string是協(xié)變到object的。下面我們來(lái)看看C# 4.0中是如何支持協(xié)方差的,在C# 4.0中定義的IEnumerable
- public interface IEnumerable : IEnumerable
- {
- IEnumerator GetEnumerator();
- }
- public interface IEnumerator : IEnumerator
- {
- bool MoveNext();
- T Current { get; }
- }
在c#的早期版本中,IEnumerable<string>不是IEnumerable<object>。注意前面Ienumerator<out T>定義中的out參數(shù),它表明普通的T只可以在輸出位置,否則編譯器就會(huì)報(bào)告錯(cuò)誤,T中的接口是協(xié)變的,意味著IEnumerable<P>也是 IEnumerable<Q>用P替換Q所得,因此,一個(gè)字符串序列也是一個(gè)對(duì)象序列,因此下面的語(yǔ)句完全有效:
IEnumerable<object> someObj = new List<string>();
下面的例子說(shuō)明了你如何在C# 4.0中使用協(xié)方差:
- namespace Test
- {
- class Base
- {
- //Methods and Properties of the Base Class
- }
- class Derived : Base
- {
- //Methods and Properties of the Derived Class
- }
- class Program
- {
- delegate T TestFunction<out T>();
- static void Main(string[] args)
- {
- TestFunction<Derived> derivedObj = () => new Derived();
- TestFunction<Base> baseObj = derivedObj;
- }
- }
- }
逆變性
C# 4.0中泛型接口的類型參數(shù)可以在in修飾字中,允許它們只出現(xiàn)在輸入位置,例如:
- public interface IComparer<in T>
- {
- public int Compare(T left, T right);
- }
因此,比較器既可以比較對(duì)象也可以比較字符串,這就叫做逆變性。逆變性的一個(gè)例子就是Equals()函數(shù)和CompareTo()函數(shù)。如果你有一個(gè)函數(shù)可以比較兩個(gè)基類的實(shí)例,那么你也可以使用它比較兩個(gè)派生類的實(shí)例,你可以在一個(gè)類型對(duì)象的實(shí)例中存儲(chǔ)任何函數(shù)調(diào)用的結(jié)果,因?yàn)镃#中函數(shù)返回的類型是逆變的。
下面是前面例子的逆變副本:
- namespace Test
- {
- class Base
- {
- }
- class Derived : Base
- {
- }
- class Program
- {
- delegate void TestDelegate<in T>(T a);
- static void Main(string[] args)
- {
- TestDelegate<Base> baseObj = (obj) => {
- System.Console.WriteLine(obj); };
- TestDelegate<Derived> derivedObj = baseObj;
- }
- }
- }
注意:類型方差只能在接口和委派類型上工作,只有在類型參數(shù)之間存在引用轉(zhuǎn)換才可以應(yīng)用方差,因此,IEnumerable<int>不是IEnumerable<object>,因?yàn)閕nt是一個(gè)值類型,object是一個(gè)引用類型,也就是說(shuō),整數(shù)到對(duì)象的轉(zhuǎn)換是箱子轉(zhuǎn)換,而不是一個(gè)引用轉(zhuǎn)換,因此它不是一個(gè)方差的例子。
正如你所看到的,C# 4.0的新特性和主互操作程序集一起可以工作得更好,對(duì)可選參數(shù)的支持意味著你不用明確地傳遞缺失值給函數(shù),而是用可選參數(shù)進(jìn)行替代,對(duì)命名參數(shù)的支持意味著不用按照特定的順序傳遞值,只要你使用了名稱就可以識(shí)別,對(duì)方差的支持消除了許多冗長(zhǎng)的,容易出錯(cuò)的強(qiáng)制類型轉(zhuǎn)換,總而言之,這些都是十分有益的變化。
【編輯推薦】





















