“is”操作符如何与动态对象一起使用?

9

is运算符在DLR方面如何工作?

为了更明确我的问题,请考虑以下签名:

 public bool Is<T>(Func<dynamic> getInstance)
 { 
     return getInstance() is T;
 }

默认情况下,Is<T> 什么条件才会返回 true?此外,DLR 是否提供了任何机制来自定义此行为?


@ReedCopsey,“细粒度鸭子类型”:我想能够做出这样的事情,即拥有一个接口 public interface INamed { string Name { get; } },并在检查 getInstance() is INamed 时,当动态对象包含名为“Name”的字符串属性时,我的自定义 DynamicMetaObject 实现将返回 true。你有什么建议吗? - smartcaveman
你需要自行实现检查,可能通过反射来对接口进行操作等。 - Reed Copsey
@smartcaveman 结构化类型与DynamicMetaObject一起使用几乎是不可能的,因为它没有测试实现的API。我编写了一个完整的库,提供了易于访问的方式来访问几乎所有C# DLR API。 - jbtule
@smartcaveman 好吧,这就是框架开始的地方,“IMyInterface myInterface = Impromptu.ActLike(expando)”。动态实现静态接口。 - jbtule
@smartcaveman 它不会在 IDynamicMetaObjectProvider 上测试接口,但是你可以在任何 IDynamicMetaObjectProvider 周围包装一个静态接口,并且该接口可以进行测试。 - jbtule
显示剩余7条评论
2个回答

6
在运行时,dynamicobject相同对待,这意味着将使用getInstance委托结果的运行时类型来执行此检查。使用dynamic的唯一区别是,在此处不会进行编译时检查,并且将在运行时使用动态绑定来对getInstance返回的动态对象执行此检查。

默认情况下,Is要满足什么条件才能返回true?

传递的委托需要返回一个在运行时与T兼容的类型。

此外,DLR是否提供任何机制来自定义此行为?

不提供。这将使用C#类型的标准规则。任何自定义行为都需要编写到逻辑本身中。


那么,结果与 typeof(T).GetType().IsInstanceOfType(getInstance()) 相同吗? - smartcaveman
@smartcaveman 更像是使用 Type.IsAssignableFrom,即:typeof(T).IsAssignableFrom(getInstance().GetType()) - Reed Copsey
在这种情况下,实际上使用object与使用其他类型没有任何区别。 - jbtule

0

由于is已经是一个运行时测试,因此不会进行任何额外的运行时绑定,实际上在编译后的IL中也不会有任何差异。

 public bool Is<T>(Func<object> getInstance)
 { 
     return getInstance() is T;
 }

Is<T>(Func<object> getInstance)Is<T>(Func<dynamic> getInstance)的方法体IL:

    .maxstack 2
    .locals init (
        [0] bool CS$1$0000)
    L_0000: nop 
    L_0001: ldarg.1 
    L_0002: callvirt instance !0 [mscorlib]System.Func`1<object>::Invoke()
    L_0007: isinst !!T
    L_000c: ldnull 
    L_000d: cgt.un 
    L_000f: stloc.0 
    L_0010: br.s L_0012
    L_0012: ldloc.0 
    L_0013: ret 

所以答案是,is关键字不受DLR使用的影响,它的工作方式与使用类型object相同。


那么完全没有编译的区别吗?如果它是DynamicObject的实例或类似的东西呢? - usr
如果它是一个DynamicObject,只有当bool Is<DynamicObject>为真时才会成立。是的,你可以编写代码,编译它,这两种方式在这种情况下将生成相同的IL。 - jbtule
我对此并不确定。DynamicObject被特殊处理。它可以用于自定义许多行为(想想ExpandoObject)。它还有一个TryConvert函数。另外,如果对象是Python对象呢?我相信Python的类型转换规则是不同的,所以它们可能是可定制的! - usr
@usr 在 C# 中不会触发类型转换。如果运行时可以进一步更改 is 的行为,那么编译器将生成动态绑定代码,但它没有这样做。我已经在答案中添加了 IL。 - jbtule

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接