C# 转换为接口类型时未调用DynamicObject.TryConvert

C# 转换为接口类型时未调用DynamicObject.TryConvert,c#,dynamic,C#,Dynamic,下面的代码引发一个异常。未调用TryConvert以转换到接口。为什么会这样?我能解决这个问题吗 using System.Dynamic; namespace ConsoleApplication1 { class Program { static void Main(string[] args) { dynamic test = new JsonNull(); var ok = (string)

下面的代码引发一个异常。未调用TryConvert以转换到接口。为什么会这样?我能解决这个问题吗

using System.Dynamic;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            dynamic test = new JsonNull();
            var ok = (string)test;
            // Next line throws:
            // Unable to cast object of type 'ConsoleApplication1.JsonNull' to type 'ConsoleApplication1.IFoo'.
            var fail = (IFoo)test;
        }
    }

    class JsonNull : DynamicObject
    {
        public override bool TryConvert(ConvertBinder binder, out object result)
        {
            result = null;
            return !binder.Type.IsValueType;
        }
    }

    interface IFoo { }
}

我怀疑这是因为在C#(可能还有.NET一般情况下)中,您无法创建到接口类型的用户定义转换(就像您无法创建到基/子类型的用户定义转换一样)。因此,每个接口转换都被视为框或引用转换

不过这只是一个猜测

编辑:另一方面,我刚刚查看了为以下内容生成的代码:

dynamic d = ...;
IDisposable x = (IDisposable) d;

它确实通过
Binder.Convert
生成了一个动态调用,所以这不是C#编译器做的。嗯。

我发现如果你改变这一行:

var fail = (IFoo)test; 
为此:

IFoo success = test;
它按预期工作

在这种情况下,似乎只有隐式转换起作用。在我看来像个虫子

我还发现这也失败了,这非常令人恼火:

class Program {
  static void Main(string[] args) {
    dynamic test = new JsonNull();
    Fails(test);
  }
  static void Fails(IFoo ifoo) { }
}
// ...

因为它看起来也应该使用隐式转换。另一个bug?

Chris Burrows在博客中解释了这种行为:

“当调用站点的底层语言为任何操作提供一些绑定时,DynamicObject(..)中还有另一个障碍,该绑定会否决可能存在的任何动态绑定

(..)回想一下,在C#(6.2.4,bullet 3)中,从大多数类类型到任何接口类型都有显式转换,尽管它们可能会失败。(..)

仅对接口转换示例进行一点扩展,它特别奇怪,因为如果转换是隐式的(比如,尝试分配给本地),那么动态转换就会工作。为什么?因为C#binder会说,“不!没有隐式转换到IEnumerable,”然后DynamicObject实现将让TryConvert完成它的任务。”


文件上怎么说?这是否得到支持?你有没有找到一种方法来解决这个问题?这也是我的直觉。我假设对接口进行强制转换并不意味着返回不同的对象实例,只是返回同一实例的不同视图。@Andrew:您可能想自己尝试实现
IDynamicMetaObjectProvider
。我不知道它是否达到了这样的程度。它还适用于返回值:
IEnumerable SomeFunc(){dynamic x=…;return x;}
在我的动态对象上调用TryConvert