本文章是由機器翻譯。

C# 4.0

.NET Framework 4 中的 C# 新功能

Chris Burrows

自 2002年在其初始版本,C# 程式設計語言已經過改良,讓程式設計人員撰寫清楚,更易於維護的程式碼。此增強功能有來自額外的功能,例如,泛型型別,可為 null 的實值型別、 Lambda 運算式、 Iterator 方法、 部分類別和一長串的其他有用的語言建構。而且通常,變更所伴隨提供對應支援的 Microsoft.NET Framework 程式庫。

這個趨勢更高的可用性會繼續在 C# 4.0。加入項目請包含泛型型別,傳統的 Interop 和更簡單的動態物件模型所使用的一般工作。這份文件的目標是要提供這些新功能的高階問卷。我泛型變異數開始,然後查看舊版和動態 Interop 功能。

共變數和 Contravariance

共變數和 contravariance 最佳引入一個的範例,最好是在架構中。在 System.Collections.Generic,IEnumerable <T> 和 IEnumerator <T> 代表,分別,’s 一連串的 T ’s 和列舉值 (或 Iterator) 的物件,不會重複順序的工作。這些介面有很長的時間來完成重型 lifting 很多,因為它們支援 foreach 迴圈建構的實作。在 C# 3.0 中它們成為更顯著因為其重要的角色,在 LINQ 和物件的 LINQ 的 — 它們 ’re.NET 介面,來代表序列。

如果您說的員工類型與類別階層架構,而 「 管理員 」 輸入,因此從它衍生 (管理員是員工,畢竟),然後會您預期要執行下列程式碼?

IEnumerable<Manager> ms = GetManagers();
IEnumerable<Employee> es = ms;

它看起來像是一個應該要能夠處理一連串的管理員,好像它是一連串的員工。 但在 C# 3.0 中,工作分派將會失敗,編譯器會告訴您有 ’s 沒有轉換。 之後就所有它有不知道 IEnumerable <T> 語意為何。 這可能是任何的介面讓 IFoo <T> 任何任意介面,為何會發生 IFoo <Manager> 是為一個 IFoo <Employee> 更多或更少 substitutable 嗎?

在 C# 4.0 不過,工作分派運作因為 IEnumerable <T>,一起幾個其他的介面已變更,啟用在 C# 中的共異變數的型別參數的新支援的變更。

IEnumerable <T> 是可為任意 IFoo <T> 比更特殊,因為雖然它 ’s 不明顯第一眼,使用型別參數 T (GetEnumerator IEnumerable <T> 中) 和在 IEnumerator <T> 目前的屬性的成員實際使用 T 只有在傳回值的位置。 因此您只取得主管出的順序,您永遠不會置於其中一個。

在相對的地把清單 <T>。 清單 <Employee> 會因為下列任一應在的嚴重損壞,讓清單 <Manager> substitutable:

List<Manager> ms = GetManagers();
List<Employee> es = ms; // Suppose this were possible
es.Add(new EmployeeWhoIsNotAManager()); // Uh oh

當顯示,一旦您認為您查看清單 <Employee>,您可以插入任何員工。 但是,有問題清單是實際清單 <Manager>,所以插入非-管理員必須失敗。 如果您允許,遺失了型別安全。 清單 <T> 不能 Covariant 在 T。

在 C# 4.0 中新的語言功能再,是能夠定義新 IEnumerable <T>,承認本身之間的轉換,當有問題的型別參數全部擲開而某些彼此的關聯性,例如的類型。 這是何種.NET Framework 開發人員撰寫 IEnumerable <T> 用,而且這是其程式碼看起來就像 (簡化,當然):

public interface IEnumerable<out T> { /* ... */ }

請注意 out 關鍵字修改定義的型別] 參數的 [T。 當編譯器所看見這時,它將 T Mark Covariant,並檢查,在介面的定義,所有使用 T 都是最新的 snuff (它們出位置只用於其他文字 —,’s 原因已選取此關鍵字)。

這是為什麼稱為共變數? 也,它 ’s 最簡單的方式請參閱開始繪製箭頭。 為了具體,let’s 使用管理員] 和 [員工] 類型。 因為有 ’s 這些類別之間的繼承關係,有 ’s 管理員將隱含參考轉換成員工:

管理員 → 員工

然後,現在,因為的 T IEnumerable < 出 T > 中的註解,有 ’s 也將 IEnumerable <Manager> 隱含參考轉換成 IEnumerable <Employee>。 ’s 註解提供的:

IEnumerable <Manager> → IEnumerable <Employee>

這稱為共變數,因為每兩個範例中的箭號指向相同的方向。 我們開始管理員和員工的兩種類型。 我們所做完它們,IEnumerable <Manager> 和 IEnumerable <Employee> 新的型別。 新的型別轉換為舊的方式相同。

在這種情況向後 Contravariance。 您可能會預期它可能發生在當型別] 參數的 [T,只作為輸入,和是正確。 就例如 System 命名空間包含介面呼叫 IComparable <T>,具有單一呼叫 CompareTo 方法:

public interface IComparable<in T> { 
  bool CompareTo(T other); 
}

如果您的 IComparable <Employee> 應該能夠處理它好像它是一個 IComparable <Manager>,因為唯一可以做的事情放置介面中的員工。 因為一位專案經理的員工放置一個管理員應該使用,它不會。 中的關鍵字,修改 T (在此情況下,這種情況下正常運作:

IComparable<Employee> ec = GetEmployeeComparer();
IComparable<Manager> mc = ec;

因為箭號了反轉這一次,這就稱為 contravariance:

管理員 → 員工
IComparable <Manager> ← IComparable <Employee>

因此語言功能是合併彙算很簡單:您可以新增在關鍵字或出每當您定義一個型別] 參數和這樣做會因此提供可用的額外轉換。 不過有某些的限制。

第一次,這適用於泛型介面,只會將委派。 在類別或結構,以這種方式,您 can’t 宣告泛型型別參數。 rationalize 這一個簡單的方法是,委派是很多像有單一的方法的介面,並在任何情況下類別會經常是適合此處理,因為欄位。 您可以將泛用類別為輸入,並根據您寫入或讀取它的一個輸出中的任何欄位。 如果這些欄位牽涉到型別參數,參數可以是既不 Covariant 也 contravariant。

第二個,每次您有一個介面或委派 Covariant 或 contravariant] 型別參數是利用您授與新轉換的輸入只類型] 引數的介面 (不其定義),使用方式是參考型別時。 對於執行個體因為 int 實值型別 IEnumerator <int> doesn’t 轉換成 IEnumerator <object>,雖然它看起來應該像:

IEnumerator <int> image: right arrow with slash  IEnumerator <object>

這個行為的原因是轉換必須保留型別表示。 如果允許 int 到物件轉換,在結果上呼叫目前的屬性就不可能,因為 int 型別的值有不同的表示堆疊上比物件參考。 所有的參考型別擁有相同的表示堆疊,不過,因此上唯一的型別引數是參考型別,產生這些額外的轉換。

很可能,大部分的 C# 開發人員願意將使用此新的語言功能 — 它們時使用某些型別從.NET Framework (IEnumerable <T>、 IComparable <T>、 函式 <T>,還有其他的動作 <T>,) 取得更多的架構類型的轉換和較少的編譯器錯誤。 然後在就其實設計與泛型介面和委派的程式庫的任何人都可以自由地使用新的中和出時適當為使用者簡化生命的型別參數。

這項功能,順帶需要從執行階段支援 — 但有一定有被支援。 因為沒有語言進行配置休眠,但是的多個版本使用它。 而且前, 一版的 C# 允許已 contravariant 某些限制的轉換。 特別,它們讓您進行委派的方法具有相容的傳回型別。 在就另外陣列型別有永遠被 Covariant。 這些現有的功能會不同於 C# 4.0,這實際上可讓您定義自己 Covariant 的型別中的新的和 contravariant 在某些型別參數。

動態分派

以 C# 4.0 Interop 功能,開頭什麼不可能是最大的變更。

C# 現在支援動態的晚期繫結。 語言永遠強別,並且繼續操作處於 4.0 版。 Microsoft 認為這樣 C# 使用簡單、 快速和適用於所有工作.NET 程式設計師都放。 但有時候,您需要與不根據.NET 的系統進行通訊。

傳統上,已至少兩種方法。 第一個只是要直接將.NET Proxy 以匯入外部索引的模型。 COM Interop 提供一個範例。 自原始發行版本的.NET Framework,它已使用工具,呼叫會直接從 C# 中建立新的.NET Proxy 類型,您可以使用的 TLBIMP 使用這項策略。

LINQ 為-SQL,隨附 C# 3.0 包含名為現有資料庫匯入使用查詢的 C# Proxy 類別的 SQLMETAL 的工具。 您也尋找將 Windows 管理檢測 (WMI) 類別匯入 C# 的工具。 許多技術可讓您撰寫 C# (通常是使用屬性),然後執行 Interop 使用手寫的程式碼為基礎,例如 LINQ 以 SQL、 Windows 通訊基礎 (WCF) 和序列化的外部動作。

第二種方法完全放棄 C# 型別系統 (字串和資料嵌入您的程式碼。 這是採取每當您撰寫的程式碼,說,叫用方法,JScript 物件上,或當您在 ADO.NET 應用程式中內嵌 SQL 查詢。 甚至時,您做此延遲到執行階段使用反映,即使 Interop 的案例是使用.NET 本身的繫結。

在 C# 中動態的關鍵字是如何處理這種方法的麻煩的回應。 let’s 開頭簡單的範例,反映。 通常,使用它需要很多的現成的基礎結構程式碼,例如:

object o = GetObject();
Type t = o.GetType();
object result = t.InvokeMember("MyMethod", 
  BindingFlags.InvokeMethod, null, 
  o, new object[] { });
int i = Convert.ToInt32(result);

使用動態關鍵字代替使用反映此方式有些物件上呼叫方法 MyMethod 您現在可以告訴編譯器請 o 視為動態,並延遲到執行階段的所有的分析。 可執行的程式碼看起來像這樣:

dynamic o = GetObject();
int i = o.MyMethod();

它的運作,及它完成很少 convoluted 的程式碼使用相同的動作。

此縮短、 簡化 C# 語法的值可能是多清除如果您查看 ScriptObject 類別支援 JScript 物件上的作業。類別有較少的參數與實際有的 Invoke 方法 (請注意不同,在 [名稱] 中) 的 Silverlight 中有更多與不同的參數除了執行 InvokeMember 方法。既不這些都需要您叫用方法,IronPython 或 IronRuby 物件或任何數目的非相同-C# 物件您可能隨附到聯繫。

除了來自動態語言的物件找出各種原本就是動態,並且具有不同的 API 支援它們,例如 HTML DOMs、 System.Xml DOM 和 XML 的 XLinq 模型的資料模型。COM 物件常常是動態的而且可以受益於執行某些編譯器分析的時間延遲。

基本上,C# 4.0 提供簡化的一致的檢視的動態作業。若要利用您只需要是指定動態確保分析的值上的所有作業將會延遲到執行階段才指定的值。

在 C# 4.0 動態是一個內建的型別,和特殊 pseudo-keyword 表示它。附註,不過,動態也是不同的變數以 var 宣告的變數實際上有一個增強式的型別,但程式設計人員已離開到編譯器找出原因。當程式設計人員使用動態時,編譯器 doesn’t 知道正在使用哪一種類型 — 程式設計人員離開至執行階段找出。

動態和 DLR

在執行階段支援這些動態作業的基礎結構稱為動態語言執行階段 (DLR)。這個新的.NET Framework 4 程式庫會像任何其他 Managed 程式庫的在 CLR 上執行。它 ’s 負責進而初始化它的語言和發生在物件之間的每個動態作業。如果動態作業 isn’t 由它發生於物件的 C# 編譯器的執行階段元件會處理繫結。簡化並不完整的架構圖表看起來 的 圖 1 所示。

圖 1 的 在最上層的 CLR 的 DLR 回合

為動態的作業如動態方法的呼叫有趣的好處是收件者物件已插入本身在執行階段繫結的機會,並可以的結果完全決定任何給定的動態作業的語意。對於執行個體,請看看下列程式碼:

dynamic d = new MyDynamicObject();
d.Bar("Baz", 3, d);

如果已定義 MyDynamicObject,如此處所示,您可以想像會發生什麼事:

class MyDynamicObject : DynamicObject {
  public override bool TryInvokeMember(
    InvokeMemberBinder binder, 
    object[] args, out object result) {

    Console.WriteLine("Method: {0}", binder.Name);
    foreach (var arg in args) {
      Console.WriteLine("Argument: {0}", arg);
    }

    result = args[0];
    return true;
  }
}

在就實際上會列印程式碼:

Method: Bar
Argument: Baz
Argument: 3
Argument: MyDynamicObject

藉由宣告為動態型別 d,有效地消耗 MyDynamicObject 執行個體的程式碼 opts 出的編譯時間檢查 d 參與的作業。 使用動態方法的 「 我 don’t 知道這要將讓我 don’t 知道什麼方法的型別或屬性有現在為何。 編譯器,請讓他們所有透過,然後找出原因您真的有物件在 Run Time 時 」。因此,呼叫列會編譯,即使編譯器 doesn’t 知道它的表示。 然後執行階段物件本身會詢問該怎麼處理這個呼叫列。 ’s 什麼 TryInvokeMember 知道如何處理。

現在,假設,而非一個 MyDynamicObject、 使用 Python 物件:

dynamic d = GetPythonObject();
d.bar("Baz", 3, d);

如果物件在此列出的檔案然後程式碼也可以,和輸出是十分相似:

def bar(*args):
  print "Method:", bar.__name__
  for x in args:
    print "Argument:", x

在涵蓋如何為每種使用動態的值的編譯器會產生一大堆程式碼來初始化,並使用 DLR CallSite。 該 CallSite 包含的所有資訊,將需要在包括方法] 名稱等的執行階段繫結這類的作業是否採用的額外資料放在檢查的內容和引數與型別相關資訊。

如果您必須維護它,此錯誤碼就是為醜陋前面所示的反映程式碼或 ScriptObject 程式碼或包含 XML 查詢的字串為每位元。 ’s 動態的功能,在 C# 中的點 — don’t 必須這樣撰寫程式碼 !

使用 [動態的關鍵字時您的程式碼可以幾乎的是您要的樣子:如要簡單的方法叫用呼叫的索引子運算子,+ 型別轉換或偶數的複合喜歡 + = 或 + +。 您甚至可以在陳述式中使用動態值 —,就例如 if(d) 和 foreach(var x in d)。 最少運算也支援,與程式碼 (例如 d & & ShortCircuited 或 d (??) ShortCircuited。

讓 DLR 提供的這一類的作業的通用基礎結構的值是您不再需要處理不同的 API,針對每個動態的模型,您要針對程式碼 — 有 ’s 只是單一的 API。 而且您甚至 don’t 需要使用它。 C# 編譯器可使用您,並,應該提供實際撰寫程式碼,您想要更多的時間 — 您必須維護在較少基礎結構程式碼表示更多的產能為您。

C# 語言會提供用來定義動態物件沒有捷徑。 在 C# 中的動態是 耗用和使用 動態物件的所有相關資訊。 試想下面的狀況:

dynamic list = GetDynamicList();
dynamic index1 = GetIndex1();
dynamic index2 = GetIndex2();
string s = list[++index1, index2 + 10].Foo();

這個程式碼會編譯,且包含大量動態作業。 第一次,有 ’s 動態的 pre-increment 上 index1,然後動態新增具有 index2。 然後動態的索引子的 get 稱為清單上。 這些作業的產品會呼叫成員 Foo。 最後,總運算式的結果是轉換為字串,並儲存在 s。 ’s 五個動態的作業,在一行中,每個分派執行階段。

每個動態作業的編譯時期型別是動態,本身,因此 「 dynamicness 」 類型的計算,計算的流程。 即使您 hadn’t 包含動態運算式多次,有仍然會動態作業的數字。 仍有五個在這一行:

string s = nonDynamicList[++index1, index2 + 10].Foo();

因為兩個索引運算式的結果是動態,索引本身也是。 因為索引的結果動態所以因此是 Foo 來呼叫。 然後因遇到而您困惑將動態的值轉換為字串。 發生這種情況動態的就說因為此物件可能是動態的一個想要執行的轉換要求表面的某些特殊的計算。

請注意,在先前的範例,C# 允許從任何動態的運算式的隱含轉換為任何型別。 為結尾的字串轉換是隱含的並不需要明確的型別轉換作業。 同樣地,任何型別可以轉換成動態隱含。

在此的尊敬動態很像物件,多] 和相似之處 don’t 那里停止。 當您的組件和需求來發出動態的變數,編譯器將會發出時,它並操作所使用的型別物件,然後特別標示。 在某些的情況下動態是種物件,別名,但它會加入額外的行為,以動態方式解析作業,當您在使用。

如果您嘗試轉換之間的差異只在動態的泛用型別和物件您可以看到這個 ; 這種轉換會永遠運作,因為在執行階段,執行個體的清單 <dynamic> 實際上是執行個體的清單 <object>:

List<dynamic> ld = new List<object>();

您也可以請參閱動態之間的相似處和物件嘗試覆寫與物件參數宣告的方法:

class C {
  public override bool Equals(dynamic obj) { 
    /* ... */ 
  }
}

雖然它可以解決您的組件中的裝飾物件,我喜歡認為的動態為真正的型別,因為它可以做為可執行大多數與它與任何其他型別,您可以執行的動作的提醒。 您可以使用它做為型別引數或,說,以傳回值。 對於執行個體此函式定義可讓您以動態方式使用函式呼叫的結果,而不需將其傳回的值放入動態的變數:

public dynamic GetDynamicThing() { 
  /* ... */ }

處理有關動態方法的更多詳細資料並將其分派,但 don’t 需要知道他們使用的功能。 重要的概念是,您可以撰寫程式碼,看起來就像 C#,而且如果您撰寫的程式碼的任何部分是動態,編譯器會保留它直到 Run Time。

我想要涵蓋一個關於動態的最後一個主題:失敗。 因為編譯器 can’t 檢查使用動態的動作是否真的有方法呼叫 Foo,它 can’t 給予您發生錯誤。 就說這 doesn’t 表示 Foo 的呼叫將會使用在執行階段。 它可能會運作,但有許多 don’t 有稱為 Foo 方法的物件。 您的運算式無法在執行階段繫結時, 繫結器使其為您提供更多或更少完全 ’s 什麼編譯器會告訴您是否 hadn’t 使用例外狀況的最佳嘗試動態開始。

請設想以下的程式碼:

try 
{
  dynamic d = "this is a string";
  d.Foo();
}
catch (Microsoft.CSharp.RuntimeBinder.RuntimeBinderException e)
{
  Console.WriteLine(e.Message);
}

這裡有一個的字串和字串清楚地不能具有方法,稱為 Foo。 當呼叫 Foo 行執行時,繫結會失敗,而您取得一個 RuntimeBinderException。 這是上一個程式列印:

'string' does not contain a definition for 'Foo'

這是完全錯誤訊息您,為 C# 程式設計師、 預期。

具名引數和選擇性參數

另一個到 C# 以外的方法現在可以支援選擇性參數的預設值,當您呼叫這種方法,您就可以省略這些參數。 您可以看到這個汽車類別的作用中:

class Car {
  public void Accelerate(
    double speed, int? gear = null, 
    bool inReverse = false) { 

    /* ... */ 
  }
}

您可以呼叫方法,這種方式:

Car myCar = new Car();
myCar.Accelerate(55);

這有完全相同的效果:

myCar.Accelerate(55, null, false);

它 ’s 相同因為編譯器會插入省略的所有預設值。

C# 4.0 也可讓您藉由依名稱指定的某些引數呼叫方法。 以此方式您可以不必也將放在它之前的所有參數的引數傳遞的引數傳遞給選擇性參數。

說出您想要呼叫 Accelerate 前往反向,但 don’t 想指定裝備參數。 也,您可以執行這項操作:

myCar.Accelerate(55, inReverse: true);

這是新的 C# 4.0 語法,而且它會 ’s 相同,如果您已寫入:

myCar.Accelerate(55, null, true);

在就實際上呼叫的方法中的參數都是選擇性的您可以使用名稱傳遞引數時。 對於執行個體這些兩個呼叫會允許和另一個完全相同:

Console.WriteLine(format: "{0:f}", arg0: 6.02214179e23);
Console.WriteLine(arg0: 6.02214179e23, format: "{0:f}");

如果您呼叫方法採用一長串的參數,您甚至可以使用名稱為排序的程式碼中的文件以協助您記住哪個參數是其中。

介面上, 選擇性的引數和具名的參數 don’t 看起來 Interop 功能。 您可以使用它們不 Interop 曾經偶數的思考。 不過,這些功能中的動機來自 Office API。 考慮範例、 Word 程式設計和文件介面上的 [另存新檔] 方法一樣簡單的項目。 這個方法具有所有的都是選擇性的 16 參數。 與舊版的 C# 若要呼叫這個方法,您必須撰寫如下所示的程式碼:

Document d = new Document();
object filename = "Foo.docx";
object missing = Type.Missing;
d.SaveAs(ref filename, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing);

現在,您可以撰寫這:

Document d = new Document();
d.SaveAs(FileName: "Foo.docx");

我會說,’s 的改進的運作方式與 API,像這樣的人。 和改善的程式設計人員需要撰寫 Office 程式的生活已明確 motivating 的因數來新增命名引數和語言的選擇性參數。

現在,時撰寫.NET 程式庫,並考慮加入具有選擇性參數的方法您面對的選擇。 您可以新增選擇性的參數,或您可以執行 C# 程式設計師還多年來做的處理:引入多載。 在 Car.Accelerate] 範例後者的決策,也可能導致您產生型別看起來像這樣:

class Car {
  public void Accelerate(uint speed) { 
    Accelerate(speed, null, false); 
  }
  public void Accelerate(uint speed, int? gear) { 
    Accelerate(speed, gear, false); 
  }
  public void Accelerate(uint speed, int? gear, 
    bool inReverse) { 
    /* ... */ 
  }
}

選取適合您寫入媒體櫃的模型是給您。 因為 C# hasn’t,直到現在來有選擇性參數,(包括.NET Framework 4) 的.NET Framework 會傾向使用多載。 如果您決定要搭配使用選擇性參數的多載,C# 多載解析已清除的關係重大的規則,來決定在任何給定的情況下呼叫的多載。

索引屬性

撰寫程式碼對 COM Interop 的 API 時,只支援一些 C# 4.0 中較小的語言功能。 在上一個圖例中的 Word Interop 就是一個例子。

C# 程式碼一定具有索引子,您可以新增到類別,以有效地在該類別的執行個體上 [[]] 運算子多載化的概念。 這個索引子的意義是也稱為一個 [預設] 索引子,因為它 isn’t 指定一個名稱,並呼叫它需要沒有名稱。 某些 COM API 也具有 aren’t 是說您 can’t 有效地呼叫它們只要使用 [] 的預設的索引子,您必須指定一個名稱。 您可以或者,為需要一些額外的引數的屬性將索引的屬性。

C# 4.0 支援 COM Interop 型別上的索引的屬性。 您 can’t C# 索引屬性中, 定義的型別,但您可以提供您執行等 COM 型別使用它們。 C# 程式碼,這看起來就像範例,請考慮在 Excel 工作表上的 「 範圍 」 屬性:

using Microsoft.Office.Interop.Excel;

class Program {
  static void Main(string[] args) {
    Application excel = new Application();
    excel.Visible = true;

    Worksheet ws = 
      excel.Workbooks.Add().Worksheets["Sheet1"];
    // Range is an indexed property
    ws.Range["A1", "C3"].Value = 123; 
    System.Console.ReadLine();
    excel.Quit();
  }
}

在此的範例範圍 [「 A1 」、 「 C3 」] isn’t 屬性,呼叫會傳回可以加上索引的事的範圍。 它 ’s 傳遞與它的 A1 和 C3 的範圍存取子的呼叫。 而且雖然值可能不會像索引屬性,太,是一! 其所有引數是選擇性的的因為它 ’s 索引的屬性時,您省略它們藉由不完全指定。 支援的語言建立索引內容之前先您會撰寫如下:

ws.get_Range("A1", "C3").Value2 = 123;

這裡,Value2 是只要新增一個屬性因為索引的屬性值 wouldn’t 運作之前,C# 4.0。

省略參考關鍵字,在 COM 呼叫站台

傳遞參考,即使實作 doesn’t 寫回至它們的許多參數與寫入某些 COM API。 在 Office] 套件 Word 突出做為範例,其所有的 COM API 執行此動作。

因遇到而您困惑這類的程式庫,並需要由參考傳遞引數時,不再可以傳遞任何運算式,不 ’s 區域變數或欄位,和的 ’s 大麻煩。 在 Word 另存新檔] 範例中您可以看到動作在這個 — 您必須宣告一個稱為 [檔名] 及 [本機呼叫遺漏只是用來呼叫另存新檔] 方法,因為參考傳遞所需的參數。

Document d = new Document();
object filename = "Foo.docx";
object missing = Type.Missing;
d.SaveAs(ref filename, ref missing, // ...

您可能已經注意到新 C# 程式碼中後, 接,我不會再宣告一個本機檔名為:

d.SaveAs(FileName: "Foo.docx");

這是可能的因為新的省略 COM Interop 的 ref 功能。現在時呼叫 COM Interop 方法,您可以傳任何引數的值,而非參考。如果您所做編譯器會替您建立暫存的本機,並傳遞的本機所參考,必要時。就說您 won’t 可以查看效果的方法呼叫,如果方法 mutates 引數 (如果需要,請以 ref 傳遞引數。

這應該要使用 API 像這個大有清楚的程式碼。

內嵌的 COM Interop 類型

這是多個 C# 語言功能,比 C# 編譯器功能,但是現在您可以使用 COM Interop 組件,而該組件必須出現在執行階段有不。目標是要降低部署您的應用程式與 COM Interop 組件的負擔。

當在原始版本的.NET Framework 中引進 COM Interop 時,建立概念的主要 Interop 組件 (PIA)。這是嘗試解決問題的共用元件之間的 COM 物件。如果您具有 [不同 Interop 組件定義的 Excel 工作表我們 wouldn’t 無法共用這些工作表元件,之間因為他們是不同的.NET 型別。PIA 修正這一次現有 — 所有的用戶端使用它,和.NET 型別永遠相符。

雖然不錯的主意,練習部署一個 PIA 結果是一個的麻煩因為 ’s 只有一個,與多個應用程式中的紙張上,可以嘗試安裝或解除安裝它。事情是複雜的因為 PIA 通常是大型、 Office doesn’t 預設的 Office 安裝與部署這些和使用者可以規避這個單一組件系統容易只要使用 TLBIMP 來建立自己的 Interop 組件。

因此就現在以修復此狀況努力中有發生兩件事:

  • 執行階段已被授與 smarts,若要將兩個結構相同 COM Interop 類型當作實際上是相同的.NET 型別共用相同的識別特性 (名稱,GUID 等等)。
  • C# 編譯器會利用這,藉由只重現 Interop 您自己的組件中的型別,當編譯,移除 Interop 組件在執行階段時存在的需要。

我有省略空間,重視的某些詳細資料,但即使沒有詳細資料的知識,這是另一項功能 — 像是動態 — 您應該可以使用,而不是問題。您告訴編譯器將內嵌 Interop 型別] 屬性設定為 true 的參考上在 Visual Studio 中嵌入 Interop 的型別為您。

因為 C# 小組可預期這是慣用的方法的參考 COM 組件,Visual Studio 將任何新的 Interop 參考加入至 C# 專案的預設就為 True 設定此屬性。如果您來建置您的程式碼使用命令列編譯器 (csc.exe),然後嵌入 Interop 類型,您必須參考 Interop 組件的問題中使用 [/L 切換而非 /R.

本身產生更多的討論每個我本文中討論的功能可能和所有主題夠資格都擁有自己的文件。我省略或 glossed 過多的詳細資料,但我希望這當做很好的開始點的瀏覽 C# 4.0 並找出時間調查,並讓使用這些功能。而且,如果您所執行我希望您在享受產能和它們的設計,讓您的程式可讀性。

Chris Burrows 是開發人員在 Microsoft C# 編譯器小組。 他實作動態 C# 編譯器中,而且已經處理九年 Visual Studio 開發

多虧了要檢閱這份文件的下列的技術專家:Eric Lippert