C#动态类型的疑难杂症 [英] C# dynamic type gotcha

查看:140
本文介绍了C#动态类型的疑难杂症的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我只是碰到了奇怪的事情,我有点 =记吹的时刻...

I just ran into the strangest thing and I'm a bit mind = blown at the moment...

下面的程序编译正常,但是当你运行它,你收到了 RuntimeBinderException 当您尝试读取对象不包含值

The following program compiles fine but when you run it you get a RuntimeBinderException when you try to read Value. 'object' does not contain a definition for '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?
    }
}



下面是令人兴奋的部分。移动嵌套类型工厂+空工厂类外,像这样:

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

class Factory...

和程序运行得很好,有人照顾解释这是为什么?

And the program runs just fine, anyone care to explain why that is?

在我的编码我当然是冒险做了我应该想到第一。这就是为什么你看到我东拉西扯了一下有关类私人和内部之间的差异。这是因为我已经将 InternalsVisibleToAttribute 这让我的测试项目(这是消耗位在这种情况下)的行为,他们做的方式,这是所有的设计,虽然暗指我从一开始。

In my adventure of coding I of course did something I should have thought about first. That's why you see me rambling a bit about the difference between class private and internal. This was because I had set the InternalsVisibleToAttribute which made my test project (which was consuming the bits in this instance) behave the way they did, which was all by design, although alluding me from the start.

阅读埃里克利珀对剩下的一个很好的解释回答。

Read Eric Lippert's answer for a good explanation of the rest.

什么抓住了我真正的后卫是动态的粘合剂发生在心中的实例的类型的可见性。我有很多的经验的JavaScript和一个JavaScript程序员那里是不是真的有这样的事情作为公共或私人的,我完全被愚弄的事实的知名度要紧,我是说毕竟我是访问这个成员,如果这是公共接口类型(我想动是反射只是语法糖),但动态粘结剂不能作这样的假设,除非你给它一个提示,使用简单的铸件。

What caught me really of guard was that the dynamic binder takes the visibility of the type of the instance in mind. I have a lot of JavaScript experience and as a JavaScript programmer where there really isn't such a thing as public or private, I was completely fooled by the fact that the visibility mattered, I mean after all, I was accessing this member as if it was of the public interface type (I thought dynamic was simply syntactic sugar for reflection) but the dynamic binder cannot make such an assumption unless you give it a hint, using a simple cast.

推荐答案

的基本原则动态在C#是:在运行时做表达式的类型分析的仿佛运行时类型已经编译时类型。所以,让我们看看如果我们真的这样做,会发生什么:

The fundamental principle of "dynamic" in C# is: at runtime do the type analysis of the expression as though the runtime type had been the compile time type. So let's see what would happen if we actually did that:

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

这计划将失败,因为空缺不是无障碍。 动态不会允许你这样做,将在第一时间已经违法了分析。

That program would fail because Empty is not accessible. dynamic will not allow you to do an analysis that would have been illegal in the first place.

然而,运行时分析仪意识到这一点,并决定骗一点点。它要求自己有一个基类的空即访问?答案是显然是肯定的。所以决定回退到基类和分析:

However, the runtime analyzer realizes this and decides to cheat a little. It asks itself "is there a base class of Empty that is accessible?" and the answer is obviously yes. So it decides to fall back to the base class and analyzes:

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



这将失败,因为该计划会给你一个对象没有一个成员叫值错误。这就是你所得到的错误。

Which fails because that program would give you an "object doesn't have a member called Value" error. Which is the error you are getting.

动态分析从来不说哦,你一定意味

The dynamic analysis never says "oh, you must have meant"

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

由于课程的如果这就是你曾经的意思,那就是你会写在首先的。同样,动态的目的是回答这个问题的会发生什么事了编译器知道运行时类型的,并转换为一个接口没有按' ŧ给你的运行时类型。

because of course if that's what you had meant, that's what you would have written in the first place. Again, the purpose of dynamic is to answer the question what would have happened had the compiler known the runtime type, and casting to an interface doesn't give you the runtime type.

当您移动空缺外面那么动态运行分析假装你写的:

When you move Empty outside then the dynamic runtime analyzer pretends that you wrote:

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



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

And now Empty is accessible and the cast is legal, so you get the expected result.

更新:

可以编译代码到一个程序集,引用该组件,如果空类型是类这将使它的内部默认

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

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

I am unable to reproduce the described behaviour. Let's try a little example:

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的访问。因此,回落到公众的基本类型,的事情,这是访问,但没有必要的财产。


And you see how this works: the runtime binder has detected that InternalThing is internal to the foreign assembly, and therefore is inaccessible in foo.exe. So it falls back to the public base type, Thing, which is accessible but does not have the necessary property.

我无法重现您所描述的行为,如果你能复制它,然后你发现了一个错误。如果你有缺陷的一个小摄制我很高兴地把它传递给我的前同事。

I'm unable to reproduce the behaviour you describe, and if you can reproduce it then you've found a bug. If you have a small repro of the bug I am happy to pass it along to my former colleagues.

这篇关于C#动态类型的疑难杂症的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆