为啥 C# 可以在运行时处理这种明显愚蠢的对象提升?
Posted
技术标签:
【中文标题】为啥 C# 可以在运行时处理这种明显愚蠢的对象提升?【英文标题】:How come C# can handle this obviously idiotic object promotion during run time?为什么 C# 可以在运行时处理这种明显愚蠢的对象提升? 【发布时间】:2017-09-02 23:28:12 【问题描述】:我非常喜欢 C# 语言。我只是在玩,永远不会在生产代码中使用下面的代码。显然编译器被结构的布局所迷惑。但是为什么 Super 类上的字符串仍然可以在运行时读写呢?我会预料到一些内存访问冲突。在运行时检查类型,它说它是 Base 类型,请参阅NoProblem()
函数执行。没有实例化 Super 类。
它怎么能这样运作?
using System;
using System.Runtime.InteropServices;
namespace Fiddle
class Program
static void Main(string[] args)
var b = new Base
IntOnBase = 1
;
var overlay = new Overlay();
overlay.Base = b;
var super = overlay.Super;
var intValue = super.IntOnBase;
super.StringOnSuper = "my test string";
var stringValue = super.StringOnSuper;
super.NoProblem();
Expressions.Fiddle();
[StructLayout(LayoutKind.Explicit)]
public struct Overlay
[FieldOffset(0)]
public Super Super;
[FieldOffset(0)]
public Base Base;
public class Super : Base
public string StringOnSuper get; set;
public void NoProblem()
Console.WriteLine("You know, I am really a " + this.GetType().Name + " kind of class.");
public class Base
public int IntOnBase get; set;
【问题讨论】:
Super 比 Base 大,如果您尝试将 Super 转换为 Base,您只会遇到问题super.StringOnSuper
在你分配它之前的值是多少?我希望它未初始化,因为Base
的构造函数不知道它。
看起来类似于this question。有人建议使用FieldOffset
应视为unsafe
。
也见于this question
这不是 C# 功能,语言规范一次也没有提及。这是 CLR 公开的一项功能。它有一个非常实际的需求,它声明了一个 union,这是一种在许多其他语言中都可用的类型。但不是 C#,联合从根本上说是类型不安全的。在例如 winapi 中得到大量使用,如果没有它,他们就无法编写 .NET Framework。在纯粹之上,C# 也是一种解决实际编程问题的非常实用的语言。现实世界并不纯粹。
【参考方案1】:
好吧,你告诉 CLR 使用 StructLayout
提前布置内存(我应该提醒一下,这是基于我今天在实验和阅读其他建议的答案后的学习)
您可以在这里看出 CLR 实际上并没有实例化任何东西。这将引发 NPE。您可以在 super 上使用构造函数。它没有被调用,也不会。
基本上你是在直接访问内存,因为string
、int
等都是内置类型,你可以安全地与它们交互。这可能需要用户更多的“意图”,而其他评论的问题都指向这需要unsafe
声明。
class Program
static void Main(string[] args)
var b = new Base
IntOnBase = 1
;
var overlay = new Overlay();
overlay.Base = b;
var super = overlay.Super;
var intValue = super.IntOnBase;
super.StringOnSuper = 8;
var stringValue = super.StringOnSuper;
System.Diagnostics.Debug.WriteLine(stringValue);
super.NoProblem();
[StructLayout(LayoutKind.Explicit)]
public struct Overlay
[FieldOffset(0)]
public Super Super;
[FieldOffset(0)]
public Base Base;
public class NewClass
public string cat get; set;
public class Super : Base
private Super imNull;
public Super()
// imNull = new Super();
System.Diagnostics.Debug.WriteLine("well i get initialized...");
public int StringOnSuper get; set;
public void NoProblem()
System.Diagnostics.Debug.Write("You know, I am really a " + this.GetType().Name + " kind of class. But my super is " + imNull.ToString() );
public class Base
public int IntOnBase get; set;
【讨论】:
以上是关于为啥 C# 可以在运行时处理这种明显愚蠢的对象提升?的主要内容,如果未能解决你的问题,请参考以下文章
为啥 Castle Windsor 拦截器会破坏 C# 动态对象上方法的运行时绑定?