本文章是由機器翻譯。

技術最前線

C# 4.0,動態關鍵字和 COM

Dino Esposito

我成長最多為 C/C + + 開發人員,特別是在 Microsoft.NET Framework 的問世之前, 我經常 chided 我同事編寫在 Visual Basic 中使用這類 weakly 鍵入的語言。

沒有的時間,當靜態輸入] 和 [強型別的的程式設計的時間以軟體快樂指數明顯的方法。但是事情的變更和今天的 C# 開發人員社群 — 到它看起來幾乎所有先前的 C/C + + 開發人員都遷移的 — 通常感覺更動態的程式設計模型不同的需求。最後的月份我會介紹 Microsoft 發佈透過 4.0 C# 和 Visual Studio 2010 的動態程式設計的一些功能。這個的月份我深入更深層部分相關的案例開始使用 C# 4.0 最吸引人的原因之一 — 在.NET Framework 內的簡單的程式設計與 COM 物件。

輕鬆存取 COM 物件

物件即為動態,當其結構和行為 aren’t 完整描述由編譯器知道徹底的靜態定義型別。無可否認地,動態文字聽起來有點泛用在此內容中,因此 let’s 看一個簡單範例。指令碼語言,如 VBScript,在下列程式碼會成功執行:

Set word = CreateObject("Word.Application")

CreateObject 函數假設字串它取得引數是 progID 的已註冊的 COM 物件。 它會建立元件的執行個體,並傳回其 IDispatch 自動化介面。 IDispatch 介面的詳細資訊永遠不會顯示在指令碼語言的層級中。 什麼問題是您可以如撰寫的程式碼:

Set word = CreateObject("Word.Application")
word.Visible = True
Set doc = word.Documents.Add()
Set selection = word.Selection
selection.TypeText "Hello, world"
selection.TypeParagraph()

doc.SaveAs(fileName)

在此的程式碼中第一次建立基礎的 Microsoft Office Word 應用程式的行為會自動執行的元件的參考。接下來,您讓 Word 主視窗顯示出來、 新增新的文件、 寫入一些文字,然後儲存某處的文件。程式碼是清楚、 讀取並,更重要的是,完全正常運作。

但是,這的運作的原因是,由於 VBScript 所提供的特定功能 — 晚期繫結。晚期繫結表示 isn’t 已知的特定的物件型別,直到執行流程叫用物件。當發生這種情況執行階段環境先確保物件上叫用的成員確實存在,並且叫用它。在實際執行程式碼之前,是由沒有初步核取佔用。

您可能知道指令碼的語言 (如 VBScript doesn’t 有一個編譯器。但是,Visual Basic (包括 CLR 版本) 年有類似的功能。我 confess 我經常 envied 我的 Visual Basic 同事的更輕鬆地使用 COM 物件的能力 — 通常有價值的應用程式需要以具有,例如 Office 的 Interop 的建置組塊。在某些的情況下在就其實我的小組最後在 Visual Basic 中,撰寫 Interop 程式碼的某些部分,即使已在 C# 中的整個應用程式。這應該是 ; 令人驚訝嗎?Isn’t polyglot 程式設計到達一個新邊境嗎?

在 Visual Basic 中,CreateObject 函式存在 (增強式) 的相容性的理由。重點是記住的早期繫結與設計以.NET 為基礎的語言。COM 互通性是.NET Framework 所處理,但是永遠不會特別支援語言關鍵字與設備的案例 — 不到 C# 4.0 為止。

C# 4.0 (和 Visual Basic),都代表晚期繫結現在已核准的作法的.NET Framework 開發人員的動態查閱功能。與動態的查閱您可以撰寫程式碼的方法、 屬性、 索引子屬性和欄位會略過靜態型別檢查會在執行階段解析的方式來存取。

C# 4.0 也會啟用選擇性參數的辨識成員宣告中的預設值。這表示當叫用具有選擇性參數的成員時,選擇性的引數可以省略。此外,依名稱以及位置,可以傳遞的引數。在一天的結尾改良的 COM 繫結,在 C# 4.0 中只是表示指令碼語言的一些常用的功能現在支援的一個否則靜態和強型別語言。我們看看如何,您可以利用新的動態關鍵字不著痕跡地操作的 COM 物件之前先 let’s 深入稍微更深入的動態型別查閱內部的技巧。

動態語言執行階段

當您宣告變數,以做為動態,在 Visual Studio 2010 時,您有沒有 IntelliSense 完全在預設的設定。有趣的是,如果您在安裝額外的工具,例如 [ReSharper 5.0 (jetbrains.com/resharper) 您可以取得關於動態物件 IntelliSense 透過某些部分資訊。圖 1 顯示程式碼編輯器使用和不使用 ReSharper。工具只會列出來定義動態型別上所顯示的成員。在非常小的動態物件是 System.Object 的執行個體。


圖 1 一個動態的 IntelliSense 物件在 Visual Studio 2010 在使用和不使用 ReSharper

let’s 請參閱編譯器遇到下列的程式碼 (程式碼是刻意一般以簡化了解實作詳細資料) 時,會發生什麼事:

class Program
{
  static void Main(string[] args) 
  { 
    dynamic x = 1;
    Console.WriteLine(x);
  }
}

在第二個的行中編譯器 doesn’t 嘗試解決符號 WriteLine,並沒有警告或錯誤狀況如會發生與傳統的靜態型別檢查。 就動態的關鍵字是而言,C# 就像一個解譯的語言。 因此,編譯器會發出一些臨機操作的程式碼,會解譯涉及動態變數或引數的運算式。  解譯器基礎上動態語言執行階段 (DLR),.NET Framework 機器的全新的元件。 若要用於更特定的術語編譯器有產生使用抽象語法支援的 DLR 為運算式樹狀架構,並將它傳遞給 DLR 程式庫,以進行處理。 在 DLR,編譯器所提供的運算式被封裝在動態更新站台物件。 站台物件是負責繫結至即時物件的方法。 圖 2 顯示前面所示的一般程式發出的實際程式碼的主要處理過的版本。

編輯和簡化的可讀性, 的 圖 2 中的程式碼,但它會顯示的什麼 gist 上。 動態的變數對應至 System.Object 執行個體,然後在 DLR 程式建立網站。 站台管理 WriteLine 方法,其參數與目標物件之間的繫結。 繫結會保留的型別程式內容中。 叫用方法 Console.WriteLine 動態的變數上,您可以叫用站台,並傳遞目標物件 (在此情況下主控台型別) 和它的參數 (在此情況下動態的變數)。 內部,站台會檢查目標物件是否真的有成員 WriteLine 可接受參數和目前儲存於變數 x 的物件一樣。 如果發生錯誤,C# 執行階段只擲回 RuntimeBinderException。

圖 2 的動態變數的真實實作

internal class Program
{
  private static void Main(string[] args)
  {
    object x = 1;

    if (MainSiteContainer.site1 == null)
    {
      MainSiteContainer.site1 = CallSite<
        Action<CallSite, Type, object>>
        .Create(Binder.InvokeMember(
          "WriteLine", 
          null, 
          typeof(Program), 
          new CSharpArgumentInfo[] { 
            CSharpArgumentInfo.Create(...) 
          }));
    }
    MainSiteContainer.site1.Target.Invoke(
      site1, typeof(Console), x);
  }

  private static class MainSiteContainer
  {
    public static CallSite<Action<CallSite, Type, object>> site1;
  }
}

使用 COM 物件

使用.NET Framework 應用程式內的 COM 物件相當容易今天的新 C# 4.0 功能。let’s 查看如何在 C# 中建立 Word 文件,並比較.NET 3.5 和.NET 4 中所需要的程式碼。範例應用程式會建立新的 Word 文件,根據指定的樣板、 填滿,並將它儲存到固定的位置。範本會包含幾個常見的資訊片段的書籤。您為目標.NET Framework 3.5 或.NET Framework 4,是否能以程式設計的方式建立 Word 文件上的第一個步驟加入 Microsoft Word 物件程式庫 (請參閱 的 圖 3)。


圖 3 Word 物件程式庫的參照

Visual Studio 2010] 和 [.NET Framework 4 之前完成這項作業您需要程式碼,例如 的 圖 4

圖 4 建立新的 Word 文件,在 C# 3.0

public static class WordDocument
{
  public const String TemplateName = @"Sample.dotx";
  public const String CurrentDateBookmark = "CurrentDate";
  public const String SignatureBookmark = "Signature";

  public static void Create(String file, DateTime now, String author)
  {
    // Must be an Object because it is passed as a ref
    Object missingValue = Missing.Value;

    // Run Word and make it visible for demo purposes
    var wordApp = new Application { Visible = true };

    // Create a new document
    Object template = TemplateName;
    var doc = wordApp.Documents.Add(ref template,
      ref missingValue, ref missingValue, ref missingValue);
    doc.Activate();

    // Fill up placeholders in the document
    Object bookmark_CurrentDate = CurrentDateBookmark;
    Object bookmark_Signature = SignatureBookmark;
    doc.Bookmarks.get_Item(ref bookmark_CurrentDate).Range.Select();
    wordApp.Selection.TypeText(current.ToString());
    doc.Bookmarks.get_Item(ref bookmark_Signature).Range.Select();
    wordApp.Selection.TypeText(author);

    // Save the document 
    Object documentName = file;
    doc.SaveAs(ref documentName,
      ref missingValue, ref missingValue, ref missingValue, 
      ref missingValue, ref missingValue, ref missingValue, 
      ref missingValue, ref missingValue, ref missingValue, 
      ref missingValue, ref missingValue, ref missingValue,
      ref missingValue, ref missingValue, ref missingValue);

    doc.Close(ref missingValue, 
      ref missingValue, ref missingValue);
    wordApp.Quit(ref missingValue, 
      ref missingValue, ref missingValue);
  }
}

若要與 COM 自動化介面互動,您會經常需要 Variant 型別。 當您互動以.NET 為基礎的應用程式內從一個 COM 自動化物件時,您可以表示變數做為一般的物件。 最後的結果是您 can’t 使用字串來表示,說,因為 Variant 參數必須傳遞的參考,您想要基礎 Word 文件的範本檔案的名稱。 您必須依靠物件而,下列所示:

Object template = TemplateName;
var doc = wordApp.Documents.Add(ref template,
  ref missingValue, ref missingValue, ref missingValue);

要考慮的第二個方面是 Visual Basic 和指令碼語言都是更多 forgiving 比 C# 3.0。 因此,就例如它們 don’t 強制您指定 COM 物件上的方法所宣告的所有參數。 上的文件集合的 Add 方法需要四個的引數,除非您的語言支援選擇性的參數,否則您 can’t 忽略它們。

如稍早提到 4.0 C# 不支援選擇性參數。 這表示只需要重新編譯程式碼,在 圖 4 與 C# 4.0 中的使用時您可能甚至重寫它並卸除執行只有一個遺漏值的所有 ref 參數,如以下所示:

Object template = TemplateName;
var doc = wordApp.Documents.Add(template);

新 C# 4.0 的 「 省略 ref 」 支援, 的 [圖 4] 中的程式碼會變得更簡單,更重要的是它變成易於閱讀和語法類似指令碼的程式碼。 圖 5 包含編輯過的版本,也是使用 C# 4.0 編譯,並產生 的 [圖 4] 中的程式碼相同的效果。

圖 5 建立新的 Word 文件,在 C# 4.0

public static class WordDocument
{
  public const String TemplateName = @"Sample.dotx";
  public const String CurrentDateBookmark = "CurrentDate";
  public const String SignatureBookmark = "Signature";

  public static void Create(string file, DateTime now, String author)
  {
    // Run Word and make it visible for demo purposes
    dynamic wordApp = new Application { Visible = true };
            
    // Create a new document
    var doc = wordApp.Documents.Add(TemplateName);
    templatedDocument.Activate();

    // Fill the bookmarks in the document
    doc.Bookmarks[CurrentDateBookmark].Range.Select();
    wordApp.Selection.TypeText(current.ToString());
    doc.Bookmarks[SignatureBookmark].Range.Select();
    wordApp.Selection.TypeText(author);

    // Save the document 
    doc.SaveAs(fileName);

    // Clean up
    templatedDocument.Close();
    wordApp.Quit();
  }
}

[圖 5] 中的程式碼可讓您使用一般的.NET Framework 型別來進行呼叫 COM 物件。再加上,選擇性參數使它甚至更簡單。

動態的關鍵字,並介紹 C# 4.0 中其他 COM Interop 功能 don’t 會一段程式碼讓一定就快,但是它可以讓您撰寫 C# 程式碼,如同它是指令碼。這項成就 COM 的物件是效能的可能的增量與一樣重要。

沒有 PIA 部署

因為.NET Framework 開頭,可以換行到 Managed 類別的 COM 物件,從.NET 架構的應用程式中使用。這種情況,您需要使用 COM 的廠商 object.PIAs 是必要的且必須在用戶端應用程式一起部署提供使用主要 Interop 組件 (PIA)。但是,更經常個不,PIA 太大並結束今天的整個的 COM API,因此安裝程式封裝它們可能不是愉快的經驗。

Visual Studio 2010 提供無 PIA 選項。否-PIA 指的是編譯器 ’s 能力內嵌您從目前的組件中的 PIA 取得所需的定義。如此一來只真正需要的定義最終的組件中找到並有 ’s 打包廠商 ’s PIA,在您的安裝程式不需要。圖 6 會顯示可讓 Visual Studio 2010 中無 PIA 的 [內容] 方塊中的選項。


圖 6 啟用否 PIA 選項,在 Visual Studio 2010

否-PIA 為基礎的 C# 4.0 稱為型別相等的功能。在就簡單類型相等表示可在執行階段被視為相等和交換使用兩個不同的型別。型別相等的典型的範例是以相同的名稱,在不同的組件中定義的兩個介面。它們 ’re 不同類型,但他們可以交互使用,只要存在相同的方法。

在 [摘要],使用 COM 物件仍然可以是昂貴的但 COM Interop 支援,C# 4.0 中的可讓您撰寫的程式碼最簡單。處理 COM 物件從.NET Framework 應用程式可讓您連線到舊版應用程式和重要的商務案例的您否則有較少的控制項。COM 會在 [.NET] Frameworok 的必要邪惡,但是動態會使它,因此較低的位元。

Dino Esposito  是的作者程式設計 ASP.NET MVC 從 Microsoft 按下並具有 coauthoredMicrosoft.NET:Architecting Applications for the Enterprise(Microsoft Press,2008) 的作者。根據在義大利,Esposito 是在世界各地的業界事件頻繁的喇叭。您可以在 聯結他的部落格weblogs.asp.net/despos.

多虧給來檢閱這份文件的技術專家下列:Alex Turner