2009-10-28 23 views
2

我有一個實現接口的對象。如果它被實現,我想調用對象的方法。這樣做的最好方法是什麼?C#:可選方法

更新 你們幾個人提到我的問題含糊不清。對於那個很抱歉。當我說「如果實施」我的意思是「如果它是可調用的」。感謝你的回答和努力人(或女孩!)。我很驚訝這個網站上有多少開發者支持。

回答

10

如果這真的是你需要它的工作方式,那麼界面是錯誤的選擇。相反,你可以有一個抽象類,從你的類派生出一個虛擬方法。虛擬允許它被覆蓋,但不需要它。由於虛擬方法具有實現,因此它不能成爲接口的一部分。

+1

子類仍然會有一個虛擬的方法實現。這將是基類的實現。 – 2009-10-28 22:34:40

12

不太清楚你的意思是「如果它被實現」。如果該方法在接口中並且您的對象實現了接口,則它必須實現該方法。

+0

必須有一個實現,但它可能只是拋出一個NotImplementedException,事實上告訴我們沒有真正的實現可用......請參閱框架中的'Stream'類(它不是接口,但抽象類,但這兩個概念是相同的)。 – Lucero 2009-10-28 18:34:58

+1

但是無論哪種方式,就編譯器而言,它仍然是實現的,那麼問題是什麼? – 2009-10-28 18:37:32

+1

我認爲在實現(可在代碼中調用)和實現(邏輯上,例如對象支持操作)之間存在混淆。我的猜測是這個問題的作者意味着後者。 – Lucero 2009-10-28 18:44:03

2

該對象的類不應該實現接口的每個方法嗎?

如果對象的類繼承自一個抽象類,它可能不會覆蓋(「實現」)某些方法。也許你正在混淆你的想法。

7

創建兩個接口,並繼承需要所有方法的兩個接口。只繼承其中一個接口,其中不需要可選方法。 您也可以創建一個基礎接口,從中您可以繼承所有接口,以供OOP使用。

10

如果你想測試一個對象實現了接口,這樣你就可以調用該方法,你能做到像這樣:

interface IFoo { void Bar(); } 

object o = GetObjectThatMayImplementIFoo(); 
IFoo foo = o as IFoo; 

if (foo != null) { 
    foo.Bar(); 
} 

我認爲這是你問的是什麼?

+3

注意模式'is'後跟一個強制轉換不鼓勵,你應該使用'as'並檢查'null'(由於運行時不會執行兩個類型轉換,所以性能更好)。 – Lucero 2009-10-28 18:37:46

+0

的確,我自己並沒有這麼做,也不確定我爲什麼這樣寫這個例子。更新! – wojo 2009-10-28 18:39:08

+0

完美,爲你+1 ...;) – Lucero 2009-10-28 18:41:28

2

與其他答案一樣,我不確定你的意思。實現接口的類最接近不能實現其中一種接口方法的方法是拋出NotImplementedException。處理這種情況的方法是在調用該方法時專門捕獲該異常。但是,接口的全部要點是定義類之間的契約,所以也許一些澄清會有所幫助。

1

你不能真正知道該方法是否實際實現(或者該類只有一個「虛擬」實現)。因此,您可以使用以下模式之一來確定是否支持特定的方法:

- >有多個接口並查看該類是否實際實現了它;這可能是對付它最乾淨的方式,但它可能讓你有大量不同的接口,這可能是不希望:

IIntfA = inst as IIntfA; 
if (inst != null) { 
    // inst seems to be implemented 
} 

- 在TryXxx風格>使用方法,它會返回如果屬實他們是成功的(如TryParse()等)。

- >使用NotImplementedException - 但請注意,捕獲這些代碼非常昂貴,應該僅用於很少執行的調用,或者預期不會執行缺少的調用。 Stream類的工作原理是這樣的,例如,如果它不能寫入(但另外還有一個屬性,告訴類支持什麼,例如Stream類中的IsWritable)。

+1

你錯過了變量名 – 2009-10-28 19:17:15

2

我的第一反應是不要這樣做。它創建了條件邏輯圍繞方法存在的可能性,它違背了C#的靜態類型並打破了一些SOLID原則。我的經歷告訴我這是走錯路的錯誤。

這樣說可以通過反射或使用wojo演示的'is/as'解決方案來完成。

這種類型的行爲可能更好地用動態語言實現。這聽起來與鴨子打字相似。我不是一個充滿活力的語言傢伙,但是如果你有單元測試的話,它可能是沒問題的。

1

嘿,夥計們,不要忘了「是」關鍵詞:P

如果一個對象實現過這樣的界面可以查看:

if (inst is IInterface) 
{ 
    // you can safely cast it 
} 

我喜歡你這樣,當然,但你也可以使用「as」關鍵字

IInterface a = inst as IInterface; 
if (a != null) 
{ 
    // use a, already casted 
} 
4

我認爲你真正想要的是一種部分方法。這些在.NET 3.5中是新的。您只需申報方法「部分」:

partial void OnLoaded(); 

該方法可以正常調用:

OnLoaded(); 

整潔的事情是,如果該方法沒有在任何地方實現,編譯器是足夠聰明,不生成呼叫。

這主要是爲LINQ to SQL和Entity Framework實現的;這允許生成的代碼(使用部分類)定義和調用方法,而不知道它們是否已實現。

用接口混合部分方法會很有趣(我沒有嘗試過),但是我的第一次嘗試是在接口中聲明一個部分方法。

+0

+1。這個答案也是我的直覺。 – Brian 2009-10-28 19:29:00

+3

我懷疑這就是他需要的。部分方法應該用於在同一類的兩個部分之間建立可選的「回調」(其中一個通常是生成的,另一個是手動編碼的)。它們有很多限制 - 僅限於私有,無效返回等。它們絕對與接口無關。 – 2009-10-28 20:04:33

+0

它們當然是爲了在部分類中使用生成的代碼而創建的。我們對原始海報的要求沒有足夠的信息來了解這是否合適。也可以將屬性設置爲私有方法的訪問器,因此「私有」不一定是缺點。 (就此而言,財產可能是解決問題的另一種方法。) – 2009-10-28 20:11:01

0

我不知道你是否正在尋找這樣的東西。這使用一個屬性,您可以標記一個方法是否實現。接下來,我向接口添加了一個擴展方法,以檢查是否實現了方法。最後,代碼將允許您詢問對象是否實現了該方法。我不喜歡這個,但它可能是你正在尋找的東西。

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Reflection; 

namespace ConsoleApplication1 
{ 
    public static class Program 
    { 
     static void Main(string[] args) 
     { 
      EmployeeA empA = new EmployeeA(); 

      if (empA.IsImplemented("TestMethod")) 
       empA.TestMethod(); 

      EmployeeB empB = new EmployeeB(); 
      if (empB.IsImplemented("TestMethod")) 
       empB.TestMethod(); 


      Console.ReadLine(); 

     } 

     public static bool IsImplemented(this IEmp emp, string methodName) 
     { 
      ImplementedAttribute impAtt; 
      MethodInfo info = emp.GetType().GetMethod(methodName); 
      impAtt = Attribute.GetCustomAttribute(info, typeof(ImplementedAttribute), false) 
         as ImplementedAttribute; 

      return (impAtt == null) ? true : impAtt.Implemented; 

     } 

    } 

    public class EmployeeA : IEmp 
    { 
     #region IEmp Members 

     [Implemented(false)] 
     public void TestMethod() 
     { 
      Console.WriteLine("Inside of EmployeeA"); 
     } 

     #endregion 
    } 

    public class EmployeeB : IEmp 
    { 
     #region IEmp Members 

     [Implemented(true)] 
     public void TestMethod() 
     { 
      Console.WriteLine("Inside of EmployeeB"); 
     } 

     #endregion 
    } 


    public class ImplementedAttribute : Attribute 
    { 
     public bool Implemented { get; set; } 

     public ImplementedAttribute():this(true) 
     { 
     } 

     public ImplementedAttribute(bool implemented) 
     { 
      Implemented = implemented; 
     } 
    } 

    public interface IEmp 
    { 
     void TestMethod(); 
    } 

} 

編輯:原作者重寫問題後,你絕對只是想實現接口保證該方法確實存在。爲了好奇,我會留下上面的代碼。

+0

Aww謝謝!非常有趣的解決方案。 – burnt1ce 2009-10-29 19:02:19

0

根據您引用對象的方式,某些成員將可見。接口可能是隱式定義的或明確定義的,也可能是由派生類實現的,並且您使用的是基類引用。換句話說,對象上的所有可用成員並不總是立即顯現出來。

所以,如果你想測試你的對象(yourObj)的某個接口(ISomething)的實現,一種選擇是使用反射測試數據類型。根據此測試的結果,您可以明確地將實現對象轉換爲接口類型並使用其成員...

if (yourObj is ISomething) 
    ((ISomething)yourObj).DoSomething(); 

這是完成的另一種方式同樣的事情(更 「羅嗦」 使用方法調用):

if (typeof(ISomething).IsAssignableFrom(yourObj.GetType())) 
    ((ISomething)yourObj).DoSomething(); 

此示例假設ISomething接口被定義爲:

public interface ISomething { 
    void DoSomething(); 
    // other members ... 
} 

在總結,這段代碼說:如果接口ISomething Is-Assignable - 從你選擇的對象,那麼你的對象實現了這個接口,因此有這些公共成員。