2009-12-09 77 views
7

我正在寫一個簡單的包裝,以「鴨」一個dynamic對象與已知的接口:有沒有C#等價於Ruby的`respond_to?`?

interface IFoo { string Bar(int fred); } 

class DuckFoo : IFoo 
{ 
    private readonly dynamic duck; 

    public DuckFoo(dynamic duck) 
    { 
     this.duck = duck; 
    } 

    public string Bar(int fred) 
    { 
     return duck.Bar(fred); 
    } 
} 

這工作得很好,如果dynamic對象可以到Bar簽名響應。但是,如果它不能僅當我打電話Bar失敗。我更希望它能更快地失敗,即在構建DuckFoo包裝器時進行參數驗證。是這樣的:

public DuckFoo(dynamic duck) 
{ 
    if(/* duck has no matching Bar method */) 
     throw new ArgumentException("duck", "Bad dynamic object"); 
    this.duck = duck; 
} 

在Ruby有一個respond_to?方法,其可以被用來測試是否有物體「有」一定的方法。有沒有辦法用C#4中的動態對象來測試它?

(我知道,即使有這個檢查欄調用可能失敗以後,因爲duck的動態性質讓它停止響應方法以後。)

回答

4

你可以檢查對象上可用的方法在施工時使用反射進行包裹。

只需調用接口上的Type.GetMethods()並傳入其中的類型,並確保存在適當的方法。


編輯:

至於建議的itowlson,對於處理動態類型,以及一個選項。如果檢查傳遞對象上是否存在IDynamicMetaObjectProvider接口,則可以調用IDynamicMetaObjectProvider.GetMetaObject()GetDynamicMemberNames(),並使用此信息。

如果界面不存在,則可以恢復爲Type.GetMethods()。

這也應該處理「動態」類型。

+0

當您執行'duck.GetType()'時,會發生什麼?如果'duck'被聲明爲'dynamic duck'?它返回什麼類型? – dtb 2009-12-09 23:12:04

+0

如果動態對象是一個.NET對象,您將獲得該對象的類型。 – 2009-12-09 23:12:07

+0

我不認爲你可以在動態對象上做類似的反射...也許如果它們是常規的CLR對象,但你不能使用來自IronRuby的對象,例如... – 2009-12-09 23:12:34

0

使用反射來檢查方法:

if (duck.GetType().GetMethod("Bar") == null) { 
    throw new ArgumentException("duck", "Bad dynamic object"); 
} 
+1

這可行,但只適用於常規的CLR對象。真正的動態對象可能沒有Bar方法,並且仍然響應該呼叫。 – 2009-12-09 23:16:03

1

我不知道一個明確的方法來檢查對象提供了具體方法。當然,你可以使用反射,但只有當對象是.NET對象時纔有效。如果你確定這是事實,而不是像前面所說的那樣,沒問題,只需在對象上調用GetType()並使用GetMethod()進行檢查。另一方面,正如你自己所說的,即使在這一點上的支票也不能保證後面的方法調用會成功,所以我認爲支票是無用的。實際上只是讓通話失敗。也可能是你的支票說對象沒有提供一個特定的方法,但後來,當你實際調用它時,它確實會這樣做。