C# 实施';是'/';as';是动态的还是至少是假的?

C# 实施';是'/';as';是动态的还是至少是假的?,c#,.net,dynamic,C#,.net,Dynamic,我有一个类型ConfigValue,它通过IDynamicMetaObjectProvider和自定义DynamicMetaObject实例的实现来公开动态接口 当然,可以将这种类型的实例视为本机类型(类似于XML元素),但也可以将其视为任何其他对象类型的实例,具体取决于XML的内容及其构建的对象类型(它是little old me构建的专有IOC) 所以 但是,至少C#(我肯定可能是所有动态感知语言)不会为“as”或“is”操作发出任何动态绑定;大概是因为DynamicMetaObject没有

我有一个类型
ConfigValue
,它通过
IDynamicMetaObjectProvider
和自定义
DynamicMetaObject
实例的实现来公开动态接口

当然,可以将这种类型的实例视为本机类型(类似于XML元素),但也可以将其视为任何其他对象类型的实例,具体取决于XML的内容及其构建的对象类型(它是little old me构建的专有IOC)

所以

但是,至少C#(我肯定可能是所有动态感知语言)不会为“as”或“is”操作发出任何动态绑定;大概是因为
DynamicMetaObject
没有用于此类测试的方法。因此,仅对静态类型信息执行类型测试,在这种情况下,静态类型信息总是失败

因此,我不得不依赖于相当丑陋的:

public DesiredType Foo(dynamic d)
 {
   try
   {
      return (DesiredType)d;
   }
   catch(Exception)
   {
     //TODO: fallback logic
   }
 }

有什么办法可以避免这里的“尝试/抓住/吞咽”模式吗!?我能想到的最好的方法是在
DynamicMetaObject
之上的东西;但必须先查询,然后再查询,以进行型式试验;这将使代码进一步爆炸

我认为这是不可能的

例如,此代码:

class Program
{
    static void Main(string[] args)
    {
        dynamic d = new object();

        var x = (Program)d;
        Console.WriteLine(x);

        var y = d as Program;
        Console.WriteLine(y);

        var z = d is Program;
        Console.WriteLine(z);
    }
}
如果我们使用Reflector对其进行反编译,我们会发现动态类型能够截取强制转换的唯一原因是C#编译器为了支持它做了大量额外的工作:

class Program
{
    private static void Main(string[] args)
    {
        object d = new object();
        if (<Main>o__SiteContainer0.<>p__Site1 == null)
        {
            <Main>o__SiteContainer0.<>p__Site1 = CallSite<Func<CallSite, object, Program>>.Create(Binder.Convert(CSharpBinderFlags.ConvertExplicit, typeof(Program), typeof(Program)));
        }
        Console.WriteLine(<Main>o__SiteContainer0.<>p__Site1.Target(<Main>o__SiteContainer0.<>p__Site1, d));

        Program y = d as Program;
        Console.WriteLine(y);

        bool z = d is Program;
        Console.WriteLine(z);
    }
}
类程序
{
私有静态void Main(字符串[]args)
{
对象d=新对象();
如果(o_uuuSiteContainer0.p_uuuSite1==null)
{
o_uuusiteContainer0.p_uuusite1=CallSite.Create(Binder.Convert(CSharpBinderFlags.ConvertExplicit,typeof(Program),typeof(Program));
}
Console.WriteLine(o_uuuSiteContainer0.p_uuSite1.Target(o_uuSiteContainer0.p_uuSite1,d));
程序y=d作为程序;
控制台写入线(y);
boolz=d是程序;
控制台写入线(z);
}
}
相比之下,
as
is
调用被简单地编译成IL指令,而没有从C#编译器获得额外的魔力


这也适用于普通铸造操作人员;将
用作
而不是强制转换将不会执行任何转换强制转换,因此永远不会更改基础对象的类型。

我编写了这个非常基本的静态方法来简化测试转换的操作,而不是不支持它

public static class DynamicHelper
{
    public static TResult As<TResult>(dynamic obj) where TResult : class
    {
        if (obj == null)
            return null;
        try
        {
            return (TResult)obj;
        }
        catch (Exception)
        {
            return null;
        }
    }
}
公共静态类动态切割器
{
公共静态TResult As(动态对象),其中TResult:class
{
if(obj==null)
返回null;
尝试
{
返回(TResult)obj;
}
捕获(例外)
{
返回null;
}
}
}

这是最重要的代码;)

和是运行时测试,它们只对继承起作用,因此它们不需要动态绑定,因为它们已经是动态的。即使没有动态关键字,您也无法使用
is
as
来测试隐式或显式转换,而且它们也无法处理
short
double
等值类型

所以你的答案是没有必要伪造它,它们对动态类型和静态类型的作用完全相同。您的
try
catch
可能是测试转换的最佳方法,捕获绑定错误是DLR在很多回退情况下已经在后台执行的操作。如果在第一次出现异常时停止,您可以在调试器中亲自查看

改进
try
捕获的最佳方法是指定确切的异常

 catch(RuntimeBinderException)
   {
     //TODO: fallback logic
   }

是的,我已经反编译并注意到as/is不能转换为动态操作;正如我在问题中所说,这可能是因为
DynamicMetaObject
没有为itI提供动态绑定,我尝试在
DynamicObject
上的
TryBinaryOperation
方法中检查
ExpressionType.TypeIs
。不走运-C#编译器总是发出IL。我认为最好的办法是提供一个
Is(Type)
Is()
方法。尽管请记住,强制转换仍然会起作用(
TryConvertTo
),因此您可以使用强制转换,而不是像
s那样使用
。@Jonathan-我最终使用了静态方法,而不是扩展动态对象/提供程序。我想知道是否有理由将此功能添加到DLR中。。。可能不会!我真的认为你应该打开它-这是一个缺点(考虑到
ExpressionType
枚举具有
TypeIs
值)。@Jonathan-你说得对-到目前为止,我的命中率是50/50,所以我可能会这么做!你能展示一下你对BindConvert的重写是如何工作的吗?谢谢。很好的一点是,它们不测试转换,这意味着动态绑定它实际上是毫无意义的
public static class DynamicHelper
{
    public static TResult As<TResult>(dynamic obj) where TResult : class
    {
        if (obj == null)
            return null;
        try
        {
            return (TResult)obj;
        }
        catch (Exception)
        {
            return null;
        }
    }
}
 catch(RuntimeBinderException)
   {
     //TODO: fallback logic
   }