程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> C#入門知識 >> 平常搜集C#接口常識(常識周全)

平常搜集C#接口常識(常識周全)

編輯:C#入門知識

平常搜集C#接口常識(常識周全)。本站提示廣大學習愛好者:(平常搜集C#接口常識(常識周全))文章只能為提供參考,不一定能成為您想要的結果。以下是平常搜集C#接口常識(常識周全)正文


第一節 接口慨述

  接口(interface)用來界說一種法式的協議。完成接口的類或許構造要與接口的界說嚴厲分歧。有了這個協議,便可以拋開編程說話的限制(實際上)。接口可以從多個基接口繼續,而類或構造可以完成多個接口。接口可以包括辦法、屬性、事宜和索引器。接口自己不供給它所界說的成員的完成。接口只指定完成該接口的類或接口必需供給的成員。
  接口比如一種模版,這類模版界說了對象必需完成的辦法,其目標就是讓這些辦法可以作為接話柄例被援用。接口不克不及被實例化。類可以完成多個接口而且經由過程這些完成的接口被索引。接口變量只能索引完成該接口的類的實例。例子:

interface IMyExample {
 string this[int index] { get ; set ; }
 event EventHandler Even ;
 void Find(int value) ;
 string Point { get ; set ; }
}
public delegate void EventHandler(object sender, Event e) ; 

  下面例子中的接口包括一個索引this、一個事宜Even、一個辦法Find和一個屬性Point。
  接口可以支撐多重繼續。就像鄙人例中,接口"IComboBox"同時從"ITextBox"和"IListBox"繼續。

interface IControl {
void Paint( ) ;
}
interface ITextBox: IControl {
void SetText(string text) ;
}
interface IListBox: IControl {
void SetItems(string[] items) ;
}
interface IComboBox: ITextBox, IListBox { } 

  類和構造可以多重實例化接口。就像鄙人例中,類"EditBox"繼續了類"Control",同時從"IDataBound"和"IControl"繼續。

interface IDataBound {
 void Bind(Binder b) ;
}
public class EditBox: Control, IControl, IDataBound {
 public void Paint( ) ;
 public void Bind(Binder b) {...}
}

  在下面的代碼中,"Paint"辦法從"IControl"接口而來;"Bind"辦法從"IDataBound"接口而來,都以"public"的身份在"EditBox"類中完成。

解釋:

1、C#中的接口是自力於類來界說的。這與 C++模子是對峙的,在 C++中接話柄際上就是籠統基類。
  2、接口和類都可以繼續多個接口。
  3、而類可以繼續一個基類,接口基本不克不及繼續類。這類模子防止了 C++的多繼續成績,C++中分歧基類中的完成能夠湧現抵觸。是以也不再須要諸如虛擬繼續和顯式感化域這類龐雜機制。C#的簡化接口模子有助於加速運用法式的開辟。
  4、一個接口界說一個只要籠統成員的援用類型。C#中一個接話柄際所做的,僅僅只存在著辦法標記,但基本就沒有履行代碼。這就暗示了不克不及實例化一個接口,只能實例化一個派生自該接口的對象。
  5、接口可以界說辦法、屬性和索引。所以,比較一個類,接口的特別性是:當界說一個類時,可以派生自多重接口,而你只能可以從唯一的一個類派生。

   接口與組件

  接口描寫了組件對外供給的辦事。在組件和組件之間、組件和客戶之間都經由過程接口停止交互。是以組件一旦宣布,它只能經由過程事後界說的接口來供給公道的、分歧的辦事。這類接口界說之間的穩固性使客戶運用開辟者可以或許結構出牢固的運用。一個組件可以完成多個組件接口,而一個特定的組件接口也能夠被多個組件來完成。
  組件接口必需是可以或許自我描寫的。這意味著組件接口應當不依附於詳細的完成,將完成和接口分別完全清除了接口的應用者和接口的完成者之間的耦合關系,加強了信息的封裝水平。同時這也請求組件接口必需應用一種與組件完成有關的說話。今朝組件接口的描寫尺度是IDL說話。
  因為接口是組件之間的協定,是以組件的接口一旦被宣布,組件臨盆者就應當盡量地堅持接口不變,任何對接白話法或語義上的轉變,都有能夠形成現有組件與客戶之間的接洽遭到損壞。
  每一個組件都是自立的,有其奇特的功效,只能經由過程接口與外界通訊。當一個組件須要供給新的辦事時,可以經由過程增長新的接口來完成。不會影響原接口已存在的客戶。而新的客戶可以從新選擇新的接口來取得辦事。

  組件化法式設計

  組件化法式設計辦法繼續並成長了面向對象的法式設計辦法。它把對象技巧運用於體系設計,對面向對象的法式設計的完成進程作了進一步的籠統。我們可以把組件化法式設計辦法用作結構體系的系統構造條理的辦法,而且可使用面向對象的辦法很便利地完成組件。
  組件化法式設計強調真實的軟件可重用性和高度的互操作性。它著重於組件的發生和拆卸,這兩方面一路組成了組件化法式設計的焦點。組件的發生進程不只僅是運用體系的需求,組件市場自己也推進了組件的成長,增進了軟件廠商的交換與協作。組件的拆卸使得軟件產物可以采取相似於搭積木的辦法疾速地樹立起來,不只可以延長軟件產物的開辟周期,同時也進步了體系的穩固性和靠得住性。

  組件法式設計的辦法有以下幾個方面的特色:

  1、編程說話和開辟情況的自力性;
  2、組件地位的通明性;
  3、組件的過程通明性;
  4、可擴大性;
  5、可重用性;
  6、具有強無力的基本舉措措施;
  7、體系一級的公共辦事;

  C#說話因為其很多長處,非常實用於組件編程。但這其實不是說C#是一門組件編程說話,也不是說C#供給了組件編程的對象。我們曾經屢次指出,組件應當具有與編程說話有關的特征。請讀者記住這一點:組件模子是一種標准,不論采取何種法式說話設計組件,都必需遵照這一標准。好比組裝盤算機的例子,只需各個廠商為我們供給的配件規格、接口相符同一的尺度,這些配件組合起來就可以協同任務,組件編程也是一樣。我們只是說,應用C#說話停止組件編程將會給我們帶來更年夜的便利。

曉得了甚麼是接口,接上去就是如何界說接口,請看下一節--界說接口。

第二節 界說接口

  從技巧上講,接口是一組包括了函數型辦法的數據構造。經由過程這組數據構造,客戶代碼可以挪用組件對象的功效。
  界說接口的普通情勢為:

[attributes] [modifiers] interface identifier [:base-list] {interface-body}[;]

解釋:

  1、attributes(可選):附加的界說性信息。
  2、modifiers(可選): 許可應用的潤飾符有 new 和四個拜訪潤飾符。分離是:new、public、protected、internal、 private。在一個接口界說中統一潤飾符不許可湧現屢次,new
潤飾符只能湧現在嵌套接口中,表現籠罩了繼續而來的同名成員。The public, protected, internal, and private 潤飾符界說了對接口的拜訪權限。
  3、指導器和事宜。
  4、identifier:接口稱號。
  5、base-list(可選):包括一個或多個顯式基接口的列表,接口間由逗號分隔。
  6、interface-body:對接口成員的界說。
  7、接口可所以定名空間或類的成員,而且可以包括以下成員的簽名: 辦法、屬性、索引器 。
  8、一個接口可從一個或多個基接口繼續。

  接口這個概念在C#和Java中異常類似。接口的症結詞是interface,一個接口可以擴大一個或許多個其他接口。依照通例,接口的名字以年夜寫字母"I"開首。上面的代碼是C#接口的一個例子,它與Java中的接口完整一樣:

interface IShape {
 void Draw ( ) ;
} 

假如你從兩個或許兩個以上的接口派生,父接口的名字列表用逗號分隔,以下面的代碼所示:

interface INewInterface: IParent1, IParent2 { }

  但是,與Java分歧,C#中的接口不克不及包括域(Field)。別的還要留意,在C#中,接口內的一切辦法默許都是公用辦法。在Java中,辦法界說可以帶有public潤飾符(即便這並不是需要),但在C#中,顯式為接口的辦法指定public潤飾符長短法的。例如,上面的C#接口將發生一個編譯毛病。

interface IShape { public void Draw( ) ; }

  上面的例子界說了一個名為IControl 的接口,接口中包括一個成員辦法Paint:

interface IControl {
 void Paint( ) ;
}

  鄙人例中,接口 IInterface從兩個基接口 IBase1 和 IBase2 繼續:

interface IInterface: IBase1, IBase2 {
 void Method1( ) ;
 void Method2( ) ;
}

  接口可由類完成。完成的接口的標識符湧現在類的基列表中。例如:

class Class: Iface, Iface {
 // class 成員。
// http://www.cnblogs.com/roucheng/
} 

  類的基列表同時包括基類和接口時,列表中起首湧現的是基類。例如:

class ClassA: BaseClass, Iface1, Iface2 {
 // class成員。
}

  以下的代碼段界說接口IFace,它只要一個辦法:

interface IFace {
 void ShowMyFace( ) ;
}

  不克不及從這個界說實例化一個對象,但可以從它派生一個類。是以,該類必需完成ShowMyFace籠統辦法:

class CFace:IFace
{
 public void ShowMyFace( ) {
  Console.WriteLine(" implementation " ) ;
 }
} 

  基接口

  一個接口可以從零或多個接口繼續,那些被稱為這個接口的顯式基接口。當一個接口有比零多的顯式基接口時,那末在接口的界說中的情勢為,接口標識符前面隨著由一個冒號":"和一個用逗號","離開的基接口標識符列表。

  接口基:

  :接口類型列表解釋:

  1、一個接口的顯式基接口必需至多同接口自己一樣可拜訪。例如,在一個公共接口的基接口中指定一個公有或外部的接口是毛病的。
  2、一個接口直接或直接地從它本身繼續是毛病的。
  3、接口的基接口都是顯式基接口,而且是它們的基接口。換句話說,基接口的聚集完整由顯式基接口和它們的顯式基接口等等構成。鄙人面的例子中

interface IControl {
 void Paint( ) ;
}
interface ITextBox: IControl {
 void SetText(string text) ;
}
interface IListBox: IControl {
 void SetItems(string[] items) ;
}
interface IComboBox: ITextBox, IListBox { } 

  IComboBox 的基接口是IControl, ITextBox, 和 IlistBox。

  4、一個接口繼續它的基接口的一切成員。換句話說,下面的接口 IComboBox 就像Paint一樣繼續成員SetText 和 SetItems。

  5、一個完成了接口的類或構造也隱含地完成了一切接口的基接口。

接口主體

  一個接口的接口主體界說接口的成員。

interface-body:
{ interface-member-declarationsopt }

  界說接口重要是界說接口成員,請看下一節--界說接口成員。

  第三節 界說接口成員

  接口可以包括一個和多個成員,這些成員可所以辦法、屬性、索引指導器和事宜,但不克不及是常量、域、操作符、結構函數或析構函數,並且不克不及包括任何靜態成員。接口界說創立新的界說空間,而且接口界說直 接包括的接口成員界說將新成員引入該界說空間。

  解釋:

  1、接口的成員是從基接口繼續的成員和由接口自己界說的成員。
  2、接口界說可以界說零個或多個成員。接口的成員必需是辦法、屬性、事宜或索引器。接口不克不及包括常數、字段、運算符、實例結構函數、析構函數或類型,也不克不及包括任何品種的靜態成員。
  3、界說一個接口,該接口關於每種能夠品種的成員都包括一個:辦法、屬性、事宜和索引器。
  4、接口成員默許拜訪方法是public。接口成員界說不克不及包括任何潤飾符,好比成員界說前不克不及加abstract,public,protected,internal,private,virtual,override 或static 潤飾符。
  5、接口的成員之間不克不及互相同名。繼續而來的成員不消再界說,但接口可以界說與繼續而來的成員同名的成員,這時候我們說接口成員籠罩了繼續而來的成員,這不會招致毛病,但編譯器會給出一個正告。封閉正告提醒的方法是在成員界說前加上一個new症結字。但假如沒有籠罩父接口中的成員,應用new 症結字會招致編譯器收回正告。
  6、辦法的稱號必需與統一接口中界說的一切屬性和事宜的稱號分歧。另外,辦法的簽名必需與統一接口中界說的一切其他辦法的簽名分歧。
  7、屬性或事宜的稱號必需與統一接口中界說的一切其他成員的稱號分歧。
  8、一個索引器的簽名必需差別於在統一接口中界說的其他一切索引器的簽名。
  9、接口辦法聲明中的屬性(attributes), 前往類型(return-type), 標識符(identifier), 和情勢參數列表(formal-parameter-lis)與一個類的辦法聲明中的那些有雷同的意義。一個接口辦法聲明不許可指定一個辦法主體,而聲明平日用一個分號停止。
  10、接口屬性聲明的拜訪符與類屬性聲明的拜訪符絕對應,除拜訪符主體平日必需用分號。是以,不管屬性是讀寫、只讀或只寫,拜訪符都完整肯定。
  11、接口索引聲明中的屬性(attributes), 類型(type), 和情勢參數列表 (formal-parameter-list)與類的索引聲明的那些有雷同的意義。

  上面例子中接口IMyTest包括了索引指導器、事宜E、 辦法F、 屬性P 這些成員:

interface IMyTest{
 string this[int index] { get; set; }
 event EventHandler E ;
 void F(int value) ;
 string P { get; set; }
}
public delegate void EventHandler(object sender, EventArgs e) ; 

  上面例子中接口IStringList包括每一個能夠類型成員的接口:一個辦法,一個屬性,一個事宜和一個索引。

public delegate void StringListEvent(IStringList sender);
public interface IStringList
{
 void Add(string s);
 int Count { get; }
 event StringListEvent Changed;
 string this[int index] { get; set; }
}

  接口成員的全權名

  應用接口成員也可采取全權名(fully qualified name)。接口的全權稱號是如許組成的。接口名加小圓點"." 再跟成員名好比關於上面兩個接口:

interface IControl {
 void Paint( ) ;
}
interface ITextBox: IControl {
 void GetText(string text) ;
}

  個中Paint 的全權名是IControl.Paint,GetText的全權名是ITextBox. GetText。固然,全權名中的成員稱號必需是在接口中曾經界說過的,好比應用ITextBox.Paint.就是不公道的。
  假如接口是名字空間的成員,全權名還必需包括名字空間的稱號。

namespace System
{
 public interface IDataTable {
  object Clone( ) ;
 }
}

  那末Clone辦法的全權名是System. IDataTable.Clone。

  界說好了接口,接上去就是如何拜訪接口,請看下一節--拜訪接口

  第四節、拜訪接口

  對接口成員的拜訪

  對接口辦法的挪用和采取索引指導器拜訪的規矩與類中的情形也是雷同的。假如底層成員的定名與繼續而來的高層成員分歧,那末底層成員將籠罩同名的高層成員。但因為接口支撐多繼續,在多繼續中,假如兩個父接口含有同名的成員,這就發生了二義性(這也恰是C#中撤消了類的多繼續機制的緣由之一),這時候須要停止顯式的界說:

using System ;
interface ISequence {
 int Count { get; set; }
}
interface IRing {
 void Count(int i) ;
}
// http://www.cnblogs.com/roucheng/
interface IRingSequence: ISequence, IRing { }
 class CTest {
  void Test(IRingSequence rs) {
   //rs.Count() ; 毛病, Count 有二義性
   //rs.Count = ; 毛病, Count 有二義性
   ((ISequence)rs).Count = ; // 准確
   ((IRing)rs).Count() ; // 准確挪用IRing.Count
  }
} 

  下面的例子中,前兩條語句rs .Count(1)和rs .Count = 1會發生二義性,從而招致編譯時毛病,是以必需顯式地給rs 指派父接口類型,這類指派在運轉時不會帶來額定的開支。

  再看上面的例子:

using System ;
interface IInteger {
 void Add(int i) ;
}
interface IDouble {
 void Add(double d) ;
}
interface INumber: IInteger, IDouble {}
 class CMyTest {
 void Test(INumber Num) {
  // Num.Add() ; 毛病
  Num.Add(.) ; // 准確
  ((IInteger)n).Add() ; // 准確
  ((IDouble)n).Add() ; // 准確
 }
}

  挪用Num.Add(1) 會招致二義性,由於候選的重載辦法的參數類型均實用。然則,挪用Num.Add(1.0) 是許可的,由於1.0 是浮點數參數類型與辦法IInteger.Add()的參數類型紛歧致,這時候只要IDouble.Add 才是實用的。不外只需參加了顯式的指派,就決不會發生二義性。

  接口的多重繼續的成績也會帶來成員拜訪上的成績。例如:

interface IBase {
 void FWay(int i) ;
}
interface ILeft: IBase {
 new void FWay (int i) ;
}
interface IRight: IBase
{ void G( ) ; }
interface IDerived: ILeft, IRight { }
class CTest {
 void Test(IDerived d) {
  d. FWay () ; // 挪用ILeft. FWay http://www.cnblogs.com/roucheng/
  ((IBase)d). FWay () ; // 挪用IBase. FWay
  ((ILeft)d). FWay () ; // 挪用ILeft. FWay
  ((IRight)d). FWay () ; // 挪用IBase. FWay
 }
}

  上例中,辦法IBase.FWay在派生的接口ILeft中被Ileft的成員辦法FWay籠罩了。所以對d. FWay (1)的挪用現實上挪用了。固然從IBase-> IRight-> IDerived這條繼續途徑下去看,ILeft.FWay辦法是沒有被籠罩的。我們只需記住這一點:一旦成員被籠罩今後,一切對其的拜訪都被籠罩今後的成員"攔阻"了。

類對接口的完成

  後面我們曾經說過,接口界說不包含辦法的完成部門。接口可以經由過程類或構造來完成。我們重要講述經由過程類來完成接口。用類來完成接口時,接口的稱號必需包括在類界說中的基類列表中。

  上面的例子給出了由類來完成接口的例子。個中ISequence 為一個隊列接口,供給了向隊列尾部添加對象的成員辦法Add( ),IRing 為一個輪回表接口,供給了向環中拔出對象的辦法Insert(object obj),辦法前往拔出的地位。類RingSquence 完成了接口ISequence 和接口IRing。

using System ;
interface ISequence {
 object Add( ) ;
}
interface ISequence {
 object Add( ) ;
}
interface IRing {
 int Insert(object obj) ;
}
class RingSequence: ISequence, IRing
{
 public object Add( ) {…}
 public int Insert(object obj) {…}
} 

  假如類完成了某個接口,類也隱式地繼續了該接口的一切父接口,不論這些父接口有無在類界說的基類表中列出。看上面的例子:

using System ;
interface IControl {
 void Paint( );
}
interface ITextBox: IControl {
 void SetText(string text);
}
interface IListBox: IControl {
 void SetItems(string[] items);
}
interface IComboBox: ITextBox, IListBox { } 

  這裡, 接口IcomboBox繼續了ItextBox和IlistBox。類TextBox不只完成了接口ITextBox,還完成了接口ITextBox 的父接口IControl。

  後面我們曾經看到,一個類可以完成多個接口。再看上面的例子:

interface IDataBound {
 void Bind(Binder b);
}
public class EditBox: Control, IControl, IDataBound {
 public void Paint( );
 public void Bind(Binder b) {...}
}

  類EditBox從類Control中派生而且完成了Icontrol和IdataBound。在後面的例子中接口Icontrol中的Paint辦法和IdataBound接口中的Bind辦法都用類EditBox中的公共成員完成。C#供給一種完成這些辦法的可選擇的門路,如許可使履行這些的類防止把這些成員設定為公共的。接口成員可以用有用的稱號來完成。例如,類EditBox可以改作辦法Icontrol.Paint和IdataBound.Bind來來完成。

public class EditBox: IControl, IDataBound {
 void IControl.Paint( ) {...}
 void IDataBound.Bind(Binder b) {...}
}

  由於經由過程內部指派接口成員完成了每一個成員,所以用這類辦法完成的成員稱為內部接口成員。內部接口成員可以只是經由過程接口來挪用。例如,Paint辦法中EditBox的完成可以只是經由過程創立Icontrol接口來挪用。

class Test {
 static void Main( ) {
  EditBox editbox = new EditBox( );
  editbox.Paint( ); //毛病: EditBox 沒有Paint 事宜
  IControl control = editbox;
  control.Paint( ); // 挪用 EditBox的Paint事宜
 }
} 

  上例中,類EditBox 從Control 類繼續並同時完成了IControl and IDataBound 接口。EditBox 中的Paint 辦法來自IControl 接口,Bind 辦法來自IDataBound 接口,兩者在EditBox 類中都作為私有成員完成。固然,在C# 中我們也能夠選擇不作為私有成員完成接口。

  假如每一個成員都顯著地指出了被完成的接口,經由過程這類門路被完成的接口我們稱之為顯式接口成員(explicit interface member)。 用這類方法我們改寫下面的例子:

public class EditBox: IControl, IDataBound {
 void IControl.Paint( ) {…}
 void IDataBound.Bind(Binder b) {…}
}

  顯式接口成員只能經由過程接口挪用。例如:

class CTest {
 static void Main( ) {
  EditBox editbox = new EditBox( ) ;
  editbox.Paint( ) ; //毛病:分歧的辦法
  IControl control = editbox;
  control.Paint( ) ; //挪用 EditBox的Paint辦法
 }
} 

  上述代碼中對editbox.Paint( )的挪用是毛病的,由於editbox 自己並沒有供給這一辦法。control.Paint( )是准確的挪用方法。

  正文:接口自己不供給所界說的成員的完成,它僅僅解釋這些成員,這些成員必需依附完成接口的類或其它接口的支撐。
  曉得了如何拜訪接口,我們還要曉得如何完成接口,要完成C#的接口,請看下一節-完成接口 

第五節、完成接口

  1、顯式完成接口成員

  為了完成接口,類可以界說顯式接口成員履行體(Explicit interface member implementations)。顯式接口成員履行體可所以一個辦法、一個屬性、一個事宜或許是一個索引指導器的界說,界說與該成員對應的全權名應堅持分歧。

using System ;
interface ICloneable {
 object Clone( ) ;
}
interface IComparable {
 int CompareTo(object other) ;
}
class ListEntry: ICloneable, IComparable {
 object ICloneable.Clone( ) {…}
 int IComparable.CompareTo(object other) {…}
}

  下面的代碼中ICloneable.Clone 和IComparable.CompareTo 就是顯式接口成員履行體。

  解釋:

  1、不克不及在辦法挪用、屬性拜訪和索引指導器拜訪中經由過程全權名拜訪顯式接口成員履行體。現實上,顯式接口成員履行體只能經由過程接口的實例,僅僅援用接口的成員稱號來拜訪。
  2、顯式接口成員履行體不克不及應用任何拜訪限制符,也不克不及加上abstract, virtual, override或static 潤飾符。
  3、顯式接口成員履行體和其他成員有著分歧的拜訪方法。由於不克不及在辦法挪用、屬性拜訪和索引指導器拜訪中經由過程全權名拜訪,顯式接口成員履行體在某種意義上是公有的。但它們又可以經由過程接口的實例拜訪,也具有必定的私有性質。
  4、只要類在界說時,把接口名寫在了基類列表中,並且類中界說的全權名、類型和前往類型都與顯式接口成員履行體完整分歧時,顯式接口成員履行體才是有用的,例如:

class Shape: ICloneable {
object ICloneable.Clone( ) {…}
int IComparable.CompareTo(object other) {…}
}

  應用顯式接口成員履行體平日有兩個目標:

  1、由於顯式接口成員履行體不克不及經由過程類的實例停止拜訪,這便可以從私有接口中把接口的完成部門零丁分別開。假如一個類只在外部應用該接口,而類的應用者不會直接應用到該接口,這類顯式接口成員履行體便可以起到感化。

  2、顯式接口成員履行體防止了接口成員之間由於同名而產生混雜。假如一個類願望對稱號和前往類型雷同的接口成員采取分歧的完成方法,這就必需要應用到顯式接口成員履行體。假如沒有顯式接口成員履行體,那末關於稱號和前往類型分歧的接口成員,類也沒法停止完成。

  上面的界說是有效的,由於Shape 界說時基類列表中沒有湧現接口IComparable。

 class Shape: ICloneable
 {
 object ICloneable.Clone( ) {…}
 }
 class Ellipse: Shape
 {
 object ICloneable.Clone( ) {…}
 } 

  在Ellipse 中界說ICloneable.Clone是毛病的,由於Ellipse即便隱式地完成了接口ICloneable,ICloneable依然沒有顯式地湧現在Ellipse界說的基類列表中。

  接口成員的全權名必需對應在接口中界說的成員。以下面的例子中,Paint的顯式接口成員履行體必需寫成IControl.Paint。

 using System ;
 interface IControl
 {
  void Paint( ) ;
 }
 interface ITextBox: IControl
 {
  void SetText(string text) ;
 }
 class TextBox: ITextBox
 {
  void IControl.Paint( ) {…}
  void ITextBox.SetText(string text) {…}
 } 

  完成接口的類可以顯式完成該接口的成員。當顯式完成某成員時,不克不及經由過程類實例拜訪該成員,而只能經由過程該接口的實例拜訪該成員。顯式接話柄現還許可法式員繼續同享雷同成員名的兩個接口,並為每一個接口成員供給一個零丁的完成。

  上面例子中同時以公制單元和英制單元顯示框的尺寸。Box類繼續 IEnglishDimensions和 IMetricDimensions兩個接口,它們表現分歧的器量衡體系。兩個接口有雷同的成員名 Length 和 Width。

  法式清單1 DemonInterface.cs

 interface IEnglishDimensions {
 float Length ( ) ;
 float Width ( ) ;
 }
 interface IMetricDimensions {
 float Length ( ) ;
 float Width ( ) ;
 }
 class Box : IEnglishDimensions, IMetricDimensions {
 float lengthInches ;
 float widthInches ;
 public Box(float length, float width) {
 lengthInches = length ;
 widthInches = width ;
 }
 float IEnglishDimensions.Length( ) {
 return lengthInches ;
 }
 float IEnglishDimensions.Width( ) {
 return widthInches ;
 }
 float IMetricDimensions.Length( ) {
 return lengthInches * .f ;
 }
 float IMetricDimensions.Width( ) {
 return widthInches * .f ;
 }
 public static void Main( ) {
 //界說一個實類對象 "myBox"::
 Box myBox = new Box(.f, .f);
 // 界說一個接口" eDimensions"::
 IEnglishDimensions eDimensions = (IEnglishDimensions) myBox;
 IMetricDimensions mDimensions = (IMetricDimensions) myBox;
 // 輸入:
 System.Console.WriteLine(" Length(in): {}", eDimensions.Length( ));
 System.Console.WriteLine(" Width (in): {}", eDimensions.Width( ));
 System.Console.WriteLine(" Length(cm): {}", mDimensions.Length( ));
 System.Console.WriteLine(" Width (cm): {}", mDimensions.Width( ));
 }
 } 

  輸入:Length(in): 30,Width (in): 20,Length(cm): 76.2,Width (cm): 50.8

  代碼評論辯論:假如願望默許器量采取英制單元,請正常完成 Length 和 Width 這兩個辦法,並從 IMetricDimensions 接口顯式完成 Length 和 Width 辦法:

 public float Length( ) {
 return lengthInches ;
 }
 public float Width( ){
 return widthInches;
 }
 float IMetricDimensions.Length( ) {
 return lengthInches * .f ;
 }
 float IMetricDimensions.Width( ) {
 return widthInches * .f ;
 } 

  這類情形下,可以從類實例拜訪英制單元,而從接話柄例拜訪公制單元:

System.Console.WriteLine("Length(in): {0}", myBox.Length( )) ;
System.Console.WriteLine("Width (in): {0}", myBox.Width( )) ;
System.Console.WriteLine("Length(cm): {0}", mDimensions.Length( )) ;
System.Console.WriteLine("Width (cm): {0}", mDimensions.Width( )) ; 

  2、繼續接話柄現

  接口具有不變性,但這其實不意味著接口不再成長。相似於類的繼續性,接口也能夠繼續和成長。

  留意:接口繼續和類繼續分歧,起首,類繼續不只是解釋繼續,並且也是完成繼續;而接口繼續只是解釋繼續。也就是說,派生類可以繼續基類的辦法完成,而派生的接口只繼續了父接口的成員辦法解釋,而沒有繼續父接口的完成,其次,C#中類繼續只許可單繼續,然則接口繼續許可多繼續,一個子接口可以有多個父接口。

  接口可以從零或多個接口中繼續。從多個接口中繼續時,用":"後跟被繼續的接口名字,多個接口名之間用","朋分。被繼續的接口應當是可以拜訪獲得的,好比從private 類型或internal 類型的接口中繼續就是不許可的。接口不許可直接或直接地從本身繼續。和類的繼續類似,接口的繼續也構成接口之間的條理構造。

  請看上面的例子:

 using System ;
 interface IControl {
 void Paint( ) ;
 }
 interface ITextBox: IControl {
 void SetText(string text) ;
 }
 interface IListBox: IControl {
 void SetItems(string[] items) ;
 }
 interface IComboBox: ITextBox, IListBox { } 

  對一個接口的繼續也就繼續了接口的一切成員,下面的例子中接口ITextBox和IListBox都從接口IControl中繼續,也就繼續了接口IControl的Paint辦法。接口IComboBox從接口ITextBox和IListBox中繼續,是以它應當繼續了接口ITextBox的SetText辦法和IListBox的SetItems辦法,還有IControl的Paint辦法。

一個類繼續了一切被它的根本類供給的接話柄現法式。

  欠亨過顯式的完成一個接口,一個派生類不克不及用任何辦法轉變它從它的根本類繼續的接口映照。例如,在聲明中

 interface IControl {
 void Paint( );
 }
 class Control: IControl {
 public void Paint( ) {...}
 }
 class TextBox: Control {
 new public void Paint( ) {...}
 } 

  TextBox 中的辦法Paint 隱蔽了Control中的辦法Paint ,然則沒有轉變從Control.Paint 到IControl.Paint 的映照,而經由過程類實例和接話柄例挪用Paint將會有上面的影響

 Control c = new Control( ) ;
 TextBox t = new TextBox( ) ;
 IControl ic = c ;
 IControl it = t ;
 c.Paint( ) ; // 影響Control.Paint( ) ;
 t.Paint( ) ; // 影響TextBox.Paint( ) ;
 ic.Paint( ) ; // 影響Control.Paint( ) ;
 it.Paint( ) ; // 影響Control.Paint( ) ; 

  然則,當一個接口辦法被映照到一個類中的虛擬辦法,派生類就弗成能籠罩這個虛擬辦法而且轉變接口的完成函數。例如,把下面的聲明從新寫為

 interface IControl {
 void Paint( ) ;
 }
 class Control: IControl {
 public virtual void Paint( ) {...}
 }
 class TextBox: Control {
 public override void Paint( ) {...}
 } 

  就會看到上面的成果:

Control c = new Control( ) ;
TextBox t = new TextBox( ) ;
IControl ic = c ;
IControl it = t ;
c.Paint( ) ; // 影響Control.Paint( );
t.Paint( ) ; // 影響TextBox.Paint( );
ic.Paint( ) ; // 影響Control.Paint( );
it.Paint( ) ; // 影響TextBox.Paint( );

  因為顯式接口成員完成法式不克不及被聲明為虛擬的,就弗成能籠罩一個顯式接口成員完成法式。一個顯式接口成員完成法式挪用別的一個辦法是有用的,而別的的誰人辦法可以被聲明為虛擬的以便讓派生類可以籠罩它。例如:

 interface IControl {
  void Paint( ) ;
 }
 class Control: IControl {
  void IControl.Paint( ) { PaintControl( ); }
  protected virtual void PaintControl( ) {...}
 }
 class TextBox: Control {
  protected override void PaintControl( ) {...}
 } 

  這裡,從Control 繼續的類可以經由過程籠罩辦法PaintControl 來對IControl.Paint 的完成法式停止特別化。

  3、從新完成接口

  我們曾經引見過,派生類可以對基類中曾經界說的成員辦法停止重載。相似的概念引入到類對接口的完成中來,叫做接口的重完成(re-implementation)。繼續了接話柄現的類可以對接口停止重完成。這個接口請求是在類界說的基類列表中湧現過的。對接口的重完成也必需嚴厲地遵照初次完成接口的規矩,派生的接口映照不會對為接口的重完成所樹立的接口映照發生任何影響。

  上面的代碼給出了接口重完成的例子:

interface IControl {
 void Paint( ) ;
 class Control: IControl
 void IControl.Paint( ) {…}
 class MyControl: Control, IControl
 public void Paint( ) {}
}

  現實上就是:Control把IControl.Paint映照到了Control.IControl.Paint上,但這其實不影響在MyControl中的重完成。在MyControl中的重完成中,IControl.Paint被映照到MyControl.Paint 之上。

  在接口的重完成時,繼續而來的私有成員界說和繼續而來的顯式接口成員的界說介入到接口映照的進程。

 using System ;
 interface IMethods {
  void F( ) ;
  void G( ) ;
  void H( ) ;
  void I( ) ;
 }
 class Base: IMethods {
  void IMethods.F( ) { }
  void IMethods.G( ) { }
  public void H( ) { }
  public void I( ) { }
 }
 class Derived: Base, IMethods {
  public void F( ) { }
  void IMethods.H( ) { }
 } 

  這裡,接口IMethods在Derived中的完成把接口辦法映照到了Derived.F,Base.IMethods.G, Derived.IMethods.H, 還有Base.I。後面我們說過,類在完成一個接口時,同時隱式地完成了該接口的一切父接口。異樣,類在重完成一個接口時同時,隱式地重完成了該接口的一切父接口。

using System ;
interface IBase {
 void F( ) ;
}
interface IDerived: IBase {
 void G( ) ;
}
class C: IDerived {
 void IBase.F( ) {
 //對F 停止完成的代碼…
}
void IDerived.G( ) {
 //對G 停止完成的代碼…
}
}
class D: C, IDerived {
 public void F( ) {
 //對F 停止完成的代碼…
}
public void G( ) {
 //對G 停止完成的代碼… http://www.cnblogs.com/roucheng/
}
} 

  這裡,對IDerived的重完成也異樣完成了對IBase的重完成,把IBase.F 映照到了D.F。

  4、映照接口

  類必需為在基類表中列出的一切接口的成員供給詳細的完成。在類中定位接口成員的完成稱之為接口映照(interface mapping )。
  映照,數學上表現逐個對應的函數關系。接口映照的寄義也是一樣,接口經由過程類來完成,那末關於在接口中界說的每個成員,都應當對應著類的一個成員來為它供給詳細的完成。

  類的成員及其所映照的接口成員之間必需知足以下前提:

  1、假如A和B都是成員辦法,那末A和B的稱號、類型、形參表(包含參數個數和每個參數的類型)都應當是分歧的。
  2、假如A和B都是屬性,那末A和B的稱號、類型應該分歧,並且A和B的拜訪器也是相似的。但假如A不是顯式接口成員履行體,A許可增長本身的拜訪器。
  3、假如A和B都是時光那末A和B的稱號、類型應該分歧。
  4、假如A和B都是索引指導器,那末A和B的類型、形參表(包含參數個數和每個參數的類型)應該分歧。並且A和B的拜訪器也是相似的。但假如A不是顯式接口成員履行體,A許可增長本身的拜訪器。

  那末,關於一個接口成員,如何肯定由哪個類的成員來完成呢?即一個接口成員映照的是哪個類的成員?在這裡,我們論述一下接口映照的進程。假定類C完成了一個接口IInterface,Member是接口IInterface中的一個成員,在定位由誰來完成接口成員Member,即Member的映照進程是如許的:

  1、假如C中存在著一個顯式接口成員履行體,該履行體與接口IInterface 及其成員Member絕對應,則由它來完成Member 成員。
  2、假如前提(1)不知足,且C中存在著一個非靜態的私有成員,該成員與接口成員Member絕對應,則由它來完成Member 成員。
  3、假如上述前提仍不知足,則在類C界說的基類列表中尋覓一個C 的基類D,用D來取代C。
  4、反復步調1-- 3 ,遍歷C的一切直接基類和非直接基類,直到找到一個知足前提的類的成員。
  5、假如依然沒有找到,則申報毛病。

  上面是一個挪用基類辦法來完成接口成員的例子。類Class2 完成了接口Interface1,類Class2 的基類Class1 的成員也介入了接口的映照,也就是說類Class2 在對接口Interface1停止完成時,應用了類Class1供給的成員辦法F來完成接口Interface1的成員辦法F:

interface Interface1 {
 void F( ) ;
}
class Class1 {
 public void F( ) { }
 public void G( ) { }
}
class Class2: Class1, Interface1 {
 new public void G( ) {}
}

  留意:接口的成員包含它本身界說的成員,並且包含該接口一切父接口界說的成員。在接口映照時,不只要對接口界說體中顯式界說的一切成員停止映照,並且要對隱式地從父接口那邊繼續來的一切接口成員停止映照。

  在停止接口映照時,還要留意上面兩點:

  1、在決議由類中的哪一個成員來完成接口成員時,類中顯式解釋的接口成員比其它成員優先完成。
  2、應用Private、protected和static潤飾符的成員不克不及介入完成接口映照。例如:

 interface ICloneable {
  object Clone( ) ;
 }
 class C: ICloneable {
  object ICloneable.Clone( ) {…}
  public object Clone( ) {…}
 } 

  例子中成員ICloneable.Clone 稱為接口ICloneable 的成員Clone 的完成者,由於它是顯式解釋的接口成員,比其它成員有著更高的優先權。

  假如一個類完成了兩個或兩個以上名字、類型和參數類型都雷同的接口,那末類中的一個成員便可能完成一切這些接口成員:

 interface IControl {
  void Paint( ) ;
 }
 interface IForm {
  void Paint( ) ;
 }
 class Page: IControl, IForm {
  public void Paint( ) {…}
 } 

  這裡,接口IControl和IForm的辦法Paint都映照到了類Page中的Paint辦法。固然也能夠分離用顯式的接口成員分離完成這兩個辦法:

 interface IControl {
  void Paint( ) ;
 }
 interface IForm {
  void Paint( ) ;
 }
 class Page: IControl, IForm {
  public void IControl.Paint( ) {
  //詳細的接話柄古代碼
 }
 public void IForm.Paint( ) {
  //詳細的接話柄古代碼 http://roucheng.cnblogs.com/
 }
 } 

  下面的兩種寫法都是准確的。然則假如接口成員在繼續中籠罩了父接口的成員,那末對該接口成員的完成便可能必需映照到顯式接口成員履行體。看上面的例子:

 interface IBase {
  int P { get; }
 }
 interface IDerived: IBase {
  new int P( ) ;
 } 

  接口IDerived從接口IBase中繼續,這時候接口IDerived 的成員辦法籠罩了父接口的成員辦法。由於這時候存在著同名的兩個接口成員,那末對這兩個接口成員的完成假如不采取顯式接口成員履行體,編譯器將沒法分辯接口映照。所以,假如某個類要完成接口IDerived,在類中必需至多界說一個顯式接口成員履行體。采取上面這些寫法都是公道的:

//一:對兩個接口成員都采取顯式接口成員履行體來完成

 class C: IDerived {
  int IBase.P
  get
  { //詳細的接話柄古代碼 }
   int IDerived.P( ){
   //詳細的接話柄古代碼 }
  } 

//二:對Ibase 的接口成員采取顯式接口成員履行體來完成

 class C: IDerived {
  int IBase.P
  get {//詳細的接話柄古代碼}
   public int P( ){
   //詳細的接話柄古代碼 }
  } 

//三:對IDerived 的接口成員采取顯式接口成員履行體來完成

 class C: IDerived{
  public int P
  get {//詳細的接話柄古代碼}
  int IDerived.P( ){
  //詳細的接話柄古代碼}
 } 

  另外一種情形是,假如一個類完成了多個接口,這些接口又具有統一個父接口,這個父接口只許可被完成一次。

 using System ;
 interface IControl {
  void Paint( ) ;
  interface ITextBox: IControl {
  void SetText(string text) ;
 }
 interface IListBox: IControl {
  void SetItems(string[] items) ;
 }
 class ComboBox: IControl, ITextBox, IListBox {
  void IControl.Paint( ) {…}
  void ITextBox.SetText(string text) {…}
  void IListBox.SetItems(string[] items) {…}
 } 

  下面的例子中,類ComboBox完成了三個接口:IControl,ITextBox和IListBox。假如以為ComboBox不只完成了IControl接口,並且在完成ITextBox和IListBox的同時,又分離完成了它們的父接口IControl。現實上,對接口ITextBox 和IListBox 的完成,分享了對接口IControl 的完成。

  我們對C#的接口有了較周全的熟悉,根本控制了如何運用C#的接口編程,但現實上,C#的不只僅運用於.NET平台,它異樣支撐之前的COM,可以完成COM類到.NET類的轉換,如C#挪用API。欲懂得這方面的常識,請看下一節-接口轉換。

  第六節、接口轉換

  C#中不只支撐.Net 平台,並且支撐COM平台。為了支撐 COM和.Net,C# 包括一種稱為屬性的奇特說話特征。一個屬性現實上就是一個 C# 類,它經由過程潤飾源代碼來供給元信息。屬性使 C# 可以或許支撐特定的技巧,如 COM 和 .Net,而不會攪擾說話標准自己。C# 供給將COM接口轉換為 C#接口的屬性類。另外一些屬性類將 COM類轉換為C# 類。履行這些轉換不須要任何 IDL 或類工場。

  如今安排的任何COM 組件都可以在接口轉換中應用。平日情形下,所需的調劑是完整主動停止的。

  特殊是,可使用運轉時可挪用包裝 (RCW) 從 .NET 框架拜訪 COM 組件。此包裝將 COM 組件供給的 COM 接口轉換為與 .NET 框架兼容的接口。關於 OLE 主動化接口,RCW 可以從類型庫中主動生成;關於非 OLE 主動化接口,開辟人員可以編寫自界說 RCW,手動將 COM 接口供給的類型映照為與 .NET 框架兼容的類型。

  應用ComImport援用COM組件

COM Interop 供給對現有 COM 組件的拜訪,而不須要修正原始組件。應用ComImport援用COM組件常包含上面 幾個方面的成績:

  1、創立 COM 對象。
  2、肯定 COM 接口能否由對象完成。
  3、挪用 COM 接口上的辦法。
  4、完成可由 COM 客戶端挪用的對象和接口。

  創立 COM 類包裝

  要使 C# 代碼援用COM 對象和接口,須要在 C# 中包括 COM 接口的界說。完成此操作的最簡略辦法是應用 TlbImp.exe(類型庫導入法式),它是一個包含在 .NET 框架 SDK 中的敕令行對象。TlbImp 將 COM 類型庫轉換為 .NET 框架元數據,從而有用地創立一個可以從任何托管說話挪用的托管包裝。用 TlbImp 創立的 .NET 框架元數據可以經由過程 /R 編譯器選項包含在 C# 外部版本中。假如應用 Visual Studio 開辟情況,則只需添加對 COM 類型庫的援用,將為您主動完成此轉換。

  TlbImp 履行以下轉換:

  1、COM coclass 轉換為具有沒有參數結構函數的 C# 類。
  2、COM 構造轉換為具有公共字段的 C# 構造。
  檢討 TlbImp 輸入的一種很好的辦法是運轉 .NET 框架 SDK 敕令行對象 Ildasm.exe(Microsoft 中央說話反匯編法式)來檢查轉換成果。

  固然 TlbImp 是將 COM 界說轉換為 C# 的首選辦法,但也不是任什麼時候候都可使用它(例如,在沒有 COM 界說的類型庫時或許 TlbImp 沒法處置類型庫中的界說時,就不克不及應用該辦法)。在這些情形下,另外一種辦法是應用 C# 屬性在 C# 源代碼中手動界說 COM 界說。創立 C# 源映照後,只需編譯 C# 源代碼便可發生托管包裝。

  履行 COM 映照須要懂得的重要屬性包含:

  1、ComImport:它將類標志為在內部完成的 COM 類。
  2、Guid:它用於為類或接口指定通用獨一標識符 (UUID)。
  3、InterfaceType,它指定接口是從 IUnknown 照樣從 IDispatch 派生。
  4、PreserveSig,它指定能否應將本機前往值從 HRESULT 轉換為 .NET 框架異常。

  聲明 COM coclass

  COM coclass 在 C# 中表現為類。這些類必需具有與其聯系關系的 ComImport 屬性。以下限制實用於這些類:
  1、類不克不及從任何其他類繼續。
  2、類不克不及完成任何接口。
  4、類還必需具無為其設置全局獨一標識符 (GUID) 的 Guid 屬性。

  以下示例在 C# 中聲明一個 coclass:

// 聲明一個COM類 FilgraphManager
[ComImport, Guid("E436EBB3-524F-11CE-9F53-0020AF0BA770")]
class FilgraphManager
{ }

  C# 編譯器將添加一個無參數結構函數,可以挪用此結構函數來創立 COM coclass 的實例。

  創立 COM 對象

  COM coclass 在 C# 中表現為具有沒有參數結構函數的類。應用 new 運算符創立該類的實例等效於在 C# 中挪用 CoCreateInstance。應用以上界說的類,便可以很輕易地實例化此類:

 class MainClass
 {
 public static void Main()
 {
 FilgraphManager filg = new FilgraphManager();
 }
 } 

  聲明 COM 接口

  COM 接口在 C# 中表現為具有 ComImport 和 Guid 屬性的接口。它不克不及在其基接口列表中包括任何接口,並且必需依照辦法在 COM 接口中湧現的次序聲明接口成員函數。

  在 C# 中聲明的 COM 接口必需包括其基接口的一切成員的聲明,IUnknown 和 IDispatch 的成員除外(.NET 框架將主動添加這些成員)。從 IDispatch 派生的 COM 接口必需用 InterfaceType 屬性予以標志。

從 C# 代碼挪用 COM 接口辦法時,公共說話運轉庫必需封送與 COM 對象之間傳遞的參數和前往值。關於每一個 .NET 框架類型均有一個默許類型,公共說話運轉庫將應用此默許類型在 COM 挪用間停止封送處置時封送。例如,C# 字符串值的默許封送處置是封送到本機類型 LPTSTR(指向 TCHAR 字符緩沖區的指針)。可以在 COM 接口的 C# 聲明中應用 MarshalAs 屬性重寫默許封送處置。

  在 COM 中,前往勝利或掉敗的經常使用辦法是前往一個 HRESULT,並在 MIDL 中有一個標志為"retval"、用於辦法的現實前往值的 out 參數。在 C#(和 .NET 框架)中,指導曾經產生毛病的尺度辦法是激發異常。
默許情形下,.NET 框架為由其挪用的 COM 接口辦法在兩種異常處置類型之間供給主動映照。

  前往值更改成標志為 retval 的參數的簽名(假如辦法沒有標志為 retval 的參數,則為 void)。

  標志為 retval 的參數從辦法的參數列表中剝離。

  任何非勝利前往值都將招致激發 System.COMException 異常。

  此示例顯示用 MIDL 聲明的 COM 接口和用 C# 聲明的統一接口(留意這些辦法應用 COM 毛病處置辦法)。

  上面是接口轉換的C#法式:

 using System.Runtime.InteropServices;
 // 聲明一個COM接口 IMediaControl
 [Guid("AB-AD-CE-BA-AFBA"),
 InterfaceType(ComInterfaceType.InterfaceIsDual)]
 interface IMediaControl // 這裡不克不及列出任何基接口
 {
 void Run();
 void Pause();
 void Stop();
 void GetState( [In] int msTimeout, [Out] out int pfs);
 void RenderFile(
 [In, MarshalAs(UnmanagedType.BStr)] string strFilename);
 void AddSourceFilter(
 [In, MarshalAs(UnmanagedType.BStr)] string strFilename,
 [Out, MarshalAs(UnmanagedType.Interface)] out object ppUnk);
 [return : MarshalAs(UnmanagedType.Interface)]
 object FilterCollection();
 [return : MarshalAs(UnmanagedType.Interface)]
 object RegFilterCollection();
 void StopWhenReady();
 } 

  若要避免 HRESULT 翻譯為 COMException,請在 C# 聲明中將 PreserveSig(true) 屬性附加到辦法。

  上面是一個應用C# 映照媒體播放機COM 對象的法式。

  法式清單2 DemonCOM.cs

using System;
using System.Runtime.InteropServices;
namespace QuartzTypeLib
{
//聲明一個COM接口 IMediaControl,此接口起源於媒體播放機COM類
[Guid("56A868B1-0AD4-11CE-B03A-0020AF0BA770"),
InterfaceType(ComInterfaceType.InterfaceIsDual)]
interface IMediaControl
{ //列出接口成員
void Run();
void Pause();
void Stop();
void GetState( [In] int msTimeout, [Out] out int pfs);
void RenderFile(
[In, MarshalAs(UnmanagedType.BStr)] string strFilename);
void AddSourceFilter(
[In, MarshalAs(UnmanagedType.BStr)] string strFilename,
[Out, MarshalAs(UnmanagedType.Interface)]
out object ppUnk);
[return: MarshalAs(UnmanagedType.Interface)]
object FilterCollection();
[return: MarshalAs(UnmanagedType.Interface)]
object RegFilterCollection();
void StopWhenReady();
}
//聲明一個COM類:
[ComImport, Guid("E436EBB3-524F-11CE-9F53-0020AF0BA770")]
class FilgraphManager //此類不克不及再繼續其它基類或接口
{
//這裡不克不及有任何代碼 ,體系主動增長一個缺省的結構函數
}
}
class MainClass
{
public static void Main(string[] args)
{
//敕令行參數:
if (args.Length != 1)
{
DisplayUsage();
return;
}
String filename = args[0];
if (filename.Equals("/?"))
{
DisplayUsage();
return;
}
// 聲明FilgraphManager的實類對象:
QuartzTypeLib.FilgraphManager graphManager =new QuartzTypeLib.FilgraphManager();
//聲明IMediaControl的實類對象::
QuartzTypeLib.IMediaControl mc =(QuartzTypeLib.IMediaControl)graphManager;
// 挪用COM的辦法:
mc.RenderFile(filename);
//運轉文件.
mc.Run();
//暫借停.
Console.WriteLine("Press Enter to continue.");
Console.ReadLine();
}
private static void DisplayUsage()
{ // 顯示
Console.WriteLine("媒體播放機: 播放 AVI 文件.");
Console.WriteLine("應用辦法: VIDEOPLAYER.EXE 文件名");
}
}

  運轉示例:

  若要顯示影片示例 Clock.avi,請應用以下敕令:

interop2 %windir%/clock.avi

  這將在屏幕上顯示影片,直到按 ENTER 鍵停滯。

  在 .NET 框架法式中經由過程DllImport應用 Win32 API
  .NET 框架法式可以經由過程靜態 DLL 進口點的方法來拜訪本機代碼庫。DllImport 屬性用於指定包括內部辦法的完成的dll 地位。

  DllImport 屬性界說以下:

 namespace System.Runtime.InteropServices
 {
  [AttributeUsage(AttributeTargets.Method)]
  public class DllImportAttribute: System.Attribute
  {
   public DllImportAttribute(string dllName) {...}
   public CallingConvention CallingConvention;
   public CharSet CharSet;
   public string EntryPoint;
   public bool ExactSpelling;
   public bool PreserveSig;
   public bool SetLastError;
   public string Value { get {...} }
  }
 } 

  解釋:

  1、DllImport只能放置在辦法聲明上。
  2、DllImport具有單個定位參數:指定包括被導入辦法的 dll 稱號的 dllName 參數。
  3、DllImport具有五個定名參數:

   a、CallingConvention 參數指導進口點的挪用商定。假如未指定 CallingConvention,則應用默許值 CallingConvention.Winapi。
   b、CharSet 參數指導用在進口點中的字符集。假如未指定 CharSet,則應用默許值 CharSet.Auto。
   c、EntryPoint 參數給出 dll 中進口點的稱號。假如未指定 EntryPoint,則應用辦法自己的稱號。
   d、ExactSpelling 參數指導 EntryPoint 能否必需與指導的進口點的拼寫完整婚配。假如未指定 ExactSpelling,則應用默許值 false。
   e、PreserveSig 參數指導辦法的簽名應該被保存照樣被轉換。當簽名被轉換時,它被轉換為一個具有 HRESULT 前往值和該前往值的一個名為 retval 的附加輸入參數的簽名。假如未指定 PreserveSig,則應用默許值 true。
   f、SetLastError 參數指導辦法能否保存 Win32"上一毛病"。假如未指定 SetLastError,則應用默許值 false。

  4、它是一次性屬性類。

  5、另外,用 DllImport 屬性潤飾的辦法必需具有 extern 潤飾符。

  上面是 C# 挪用 Win32 MessageBox 函數的示例:

 using System;
 using System.Runtime.InteropServices;
 class MainApp
 { //經由過程DllImport援用user.dll類。MessageBox來自於user.dll類
  [DllImport("user.dll", EntryPoint="MessageBox")]
  public static extern int MessageBox(int hWnd, String strMessage, String strCaption, uint uiType);
  public static void Main()
  {
   MessageBox( , "您好,這是 PInvoke!", ".NET", );
  }
 } 

  面向對象的編程說話簡直都用到了籠統類這一概念,籠統類為完成籠統事物供給了更年夜的靈巧性。C#也不破例, C#經由過程籠罩虛接口的技巧深化了籠統類的運用。欲懂得這方面的常識,請看下一節-籠罩虛接口

  第七節、籠罩虛接口

  有時刻我們須要表達一種籠統的器械,它是一些器械的歸納綜合,但我們又不克不及真實的看到它成為一個實體在我們面前湧現,為此面向對象的編程說話便有了籠統類的概念。C#作為一個面向對象的說話,必定也會引入籠統類這一概念。接口和籠統類使您可以創立組件交互的界說。經由過程接口,可以指定組件必需完成的辦法,但不現實指定若何完成辦法。籠統類使您可以創立行動的界說,同時供給用於繼續類的一些公共完成。關於在組件中完成多態行動,接口和籠統類都是很有效的對象。

  一個籠統類必需為類的根本類列表中列出的接口的一切成員供給完成法式。然則,一個籠統類被許可把接口辦法映照到籠統辦法中。例如

 interface IMethods {
  void F();
  void G();
 }
 abstract class C: IMethods
 {
  public abstract void F();
  public abstract void G();
 } 

  這裡, IMethods 的完成函數把F和G映照到籠統辦法中,它們必需在從C派生的非籠統類中被籠罩。

留意顯式接口成員完成函數不克不及是籠統的,然則顯式接口成員完成函數固然可以挪用籠統辦法。例如

 interface IMethods
 {
  void F();
  void G();
 }
 abstract class C: IMethods
 {
  void IMethods.F() { FF(); }
  void IMethods.G() { GG(); }
  protected abstract void FF();
  protected abstract void GG();
 }
  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved