我刚遇到最奇怪的事情,我有点心思=此刻...
下面的程序编译得很好,但是当你运行它时,你会RuntimeBinderException在尝试阅读时得到一个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?
}
}
Run Code Online (Sandbox Code Playgroud)
这是令人兴奋的部分.将嵌套类型移到类的Factory+Empty外部Factory,如下所示:
class Empty : IContainer
{
public int Value
{
get { return 0; }
}
}
class Factory...
Run Code Online (Sandbox Code Playgroud)
程序运行得很好,有人在乎解释为什么会这样吗?
在我的编码冒险中,我当然做了一些我应该首先考虑的事情.这就是为什么你看到我对私人课程和内部课程之间的差异进行了一些讨论.这是因为我设置了InternalsVisibleToAttribute哪个使我的测试项目(在这个例子中消耗了比特)表现得像他们那样,这完全是设计的,尽管从一开始就暗指我.
请阅读Eric Lippert的答案,以便对其余部分进行详细解释.
真正引起我注意的是动态绑定器考虑了实例类型的可见性.我有很多JavaScript经验,作为一个JavaScript程序员,真的没有公共或私人这样的东西,我完全被可见性很重要的事实所迷惑,我的意思是,毕竟,我正在访问这个成员,好像它是公共接口类型(我认为动态只是用于反射的语法糖)但动态绑定器不能做出这样的假设,除非你使用简单的强制转换给它一个提示.
Eri*_*ert 15
C#中"动态"的基本原则是:在运行时对表达式进行类型分析,就好像运行时类型是编译时类型一样.那么让我们看看如果我们真的这样做会发生什么:
dynamic num0 = ((Program.Factory.Empty)container).Value;
Run Code Online (Sandbox Code Playgroud)
该程序将失败,因为Empty无法访问.dynamic不允许你做一个本来就是非法的分析.
但是,运行时分析器意识到这一点,并决定作弊.它问自己"是否有一个可以访问的基类?" 答案显然是肯定的.所以它决定回到基类并分析:
dynamic num0 = ((System.Object)container).Value;
Run Code Online (Sandbox Code Playgroud)
哪个失败是因为该程序会给你一个"对象没有名为Value的成员"错误.你得到的错误是哪个.
动态分析永远不会说"哦,你一定有意"
dynamic num0 = ((Program.IContainer)container).Value;
Run Code Online (Sandbox Code Playgroud)
因为当然如果这就是你的意思,那就是你本来会写的.同样,目的dynamic是回答问题如果编译器已知运行时类型会发生什么,并且转换为接口不会为您提供运行时类型.
当你搬到Empty外面时,动态运行时分析器假装你写了:
dynamic num0 = ((Empty)container).Value;
Run Code Online (Sandbox Code Playgroud)
现在Empty可以访问,演员表是合法的,所以你得到了预期的结果.
更新:
可以将该代码编译成一个程序集,引用这个程序集,如果Empty类型在类之外,它将在默认情况下使其成为内部类
我无法重现所描述的行为.我们来试试一个例子:
public class Factory
{
public static Thing Create()
{
return new InternalThing();
}
}
public abstract class Thing {}
internal class InternalThing : Thing
{
public int Value {get; set;}
}
Run Code Online (Sandbox Code Playgroud)
> csc /t:library bar.cs
Run Code Online (Sandbox Code Playgroud)
class P
{
static void Main ()
{
System.Console.WriteLine(((dynamic)(Factory.Create())).Value);
}
}
Run Code Online (Sandbox Code Playgroud)
> csc foo.cs /r:bar.dll
> foo
Unhandled Exception: Microsoft.CSharp.RuntimeBinder.RuntimeBinderException:
'Thing' does not contain a definition for 'Value'
Run Code Online (Sandbox Code Playgroud)
并且您看到它是如何工作的:运行时绑定程序检测InternalThing到外部程序集内部,因此在foo.exe中无法访问.所以它回退到公共基础类型,Thing可以访问但没有必要的属性.
我无法重现您描述的行为,如果您可以重现它,那么您就发现了一个错误.如果你有一个小错误的bug,我很乐意将它传递给我以前的同事.
| 归档时间: |
|
| 查看次数: |
1850 次 |
| 最近记录: |