C#动态类型

我刚刚遇到了最奇怪的事情,我有点脑筋=目前吹了…

以下程序编译正常,但是当您运行它时,当您尝试读取值时,会得到一个RuntimeBinderException。 ‘object’不包含’Value’的定义

class Program
{
    interface IContainer
    {
        int Value { get; }
    }

    class Factory
    {
        class Empty : IContainer
        {
            public int Value
            {
                get { return 0; }
            }
        }

        static IContainer nullObj = new Empty();

        public IContainer GetContainer()
        {
            return nullObj;
        }
    }

    static void Main(string[] args)
    {
        dynamic factory = new Factory();
        dynamic container = factory.GetContainer();
        var num0 = container.Value; // WTF!? RuntimeBinderException, really?
    }
}

这里是心灵的一部分。在Factory类外面移动嵌套类型Factory Empty,如下所示:

class Empty : IContainer
{
    public int Value
    {
        get { return 0; }
    }
}

class Factory...

程序运行正常,任何人都在意解释为什么是这样的?

编辑

在我的编码冒险中,我当然做了一些我应该想到的第一个。这就是为什么你看到我对私人和内部阶层之间的区别进行了漫游。这是因为我设置了InternalsVisibleToAttribute,这使得我的测试项目(在这个实例中消耗了一点)的行为方式,这是所有的设计,虽然暗示我从一开始。

阅读Eric Lippert的答案,对其余的很好的解释。

令我真正感到尴尬的是,动态绑定器可以看到实例的类型。我有很多的JavaScript经验和作为一个JavaScript程序员,其实真的没有这样的公共或私人的事情,我被完全愚弄的事实,可见性是重要的,我的意思是,毕竟,我正在访问这个成员,就像它是公共接口类型(我认为动态只是反思的语法糖),但是动态绑定器不能做出这样的假设,除非你给出一个提示,使用简单的转换。

C#中的“动态”的基本原理是:在运行时执行表达式的类型分析,就像运行时类型一直是编译时类型一样。所以我们来看看如果我们这样做会发生什么:

    dynamic num0 = ((Program.Factory.Empty)container).Value;

该程序将失败,因为空不可访问。动态的将不允许您进行首先被非法的分析。

然而,运行时间分析器意识到这一点,并决定作弊一点。它问自己“有空的基础类是可以访问的?”答案显然是对的。所以决定回到基础课,分析:

    dynamic num0 = ((System.Object)container).Value;

哪个失败,因为该程序会给你一个“对象没有一个名为Value”的错误。你正在得到什么错误?

动态分析从不说“哦,你一定有意思”

    dynamic num0 = ((Program.IContainer)container).Value;

因为当然如果这是你的意思,那就是你首先写的。再次,动态的目的是回答问题,如果编译器知道运行时类型,将会发生什么,并且转换到接口不会给你运行时类型。

当您将空移出时,动态运行时分析器假装您写:

    dynamic num0 = ((Empty)container).Value;

而现在空可以访问,演员是合法的,所以你得到预期的结果。

更新:

can compile that code into an assembly, reference this assembly and it will work if the Empty type is outside of the class which would make it internal by default

我无法重现描述的行为。我们来尝试一个例子:

public class Factory
{
    public static Thing Create()
    {
        return new InternalThing();
    }
}
public abstract class Thing {}
internal class InternalThing : Thing
{
    public int Value {get; set;}
}
> csc /t:library bar.cs
class P
{
    static void Main ()
    {
        System.Console.WriteLine(((dynamic)(Factory.Create())).Value);
    }
}
> csc foo.cs /r:bar.dll
> foo
Unhandled Exception: Microsoft.CSharp.RuntimeBinder.RuntimeBinderException: 
'Thing' does not contain a definition for 'Value'

并且您看到这是如何工作的:运行时绑定器检测到InternalThing是外部程序集的内部,因此在foo.exe中是无法访问的。所以它回到公共基础类型,Thing,它是可访问的,但没有必要的属性。

我无法重现你所描述的行为,如果可以重现,那么你发现了一个错误。如果你有一个小错误,我很乐意将它传递给我的前同事。

http://stackoverflow.com/questions/15338429/c-sharp-dynamic-type-gotcha

本站文章除注明转载外,均为本站原创或编译
转载请明显位置注明出处:C#动态类型