2009-12-09 51 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()进行检查。另一方面,正如你自己所说的,即使在这一点上的支票也不能保证后面的方法调用会成功,所以我认为支票是无用的。实际上只是让通话失败。也可能是你的支票说对象没有提供一个特定的方法,但后来,当你实际调用它时,它确实会这样做。