C# FatalExecutionEngineer在处理结构布局时出错

C# FatalExecutionEngineer在处理结构布局时出错,c#,dynamic,structlayout,C#,Dynamic,Structlayout,我在到处乱搞结构布局,我发现了一些我觉得很奇怪的事情: 以下代码按照我的预期工作: using System; using System.Runtime.InteropServices; public class Program { [STAThread] static void Main() { Magic m = new Magic { InstanceA = new ClassA(),

我在到处乱搞结构布局,我发现了一些我觉得很奇怪的事情:

以下代码按照我的预期工作:

using System;
using System.Runtime.InteropServices;
public class Program
{
    [STAThread]
    static void Main()
    {
        Magic m = new Magic 
        { 
            InstanceA = new ClassA(), 
            InstanceB = new ClassB {Value="47"} 
        };

        Console.WriteLine(m.InstanceA.Value);
        Console.ReadKey();
    }

    class ClassA
    {
        public dynamic Value;
    }

    class ClassB
    {
        public string Value; // Change to int and it will get messy
    }

    [StructLayout(LayoutKind.Explicit)]
    struct Magic
    {
        [FieldOffset(0)]
        public ClassA InstanceA;
        [FieldOffset(0)]
        public ClassB InstanceB;
    }
}
但是,如果将classB.Value更改为int,则此代码将抛出前面提到的FatalExecutionEngineError


有人能解释一下为什么或者如何工作吗?我知道这可能太复杂了,我只是在这里胡闹,但有些人可能需要一些挑战。

基本上,你所做的是完全没有定义的。你在用两种非常恶劣的方式欺骗它:

  • 通过假装一个非null类引用实际上是另一种类型(但是在不进行类型检查的情况下)
  • 通过让它尝试从
    int
    加载
    对象
    引用(
    dynamic
    只是
    对象
    ,具有一些奇特的编译器技巧)(注意:在所有情况下,这很可能指向垃圾;在x64的情况下,它甚至不是整个宽度,因此它将垃圾读入要取消引用的值中
基本上:不要这样做。这就是为什么显式布局被视为无法验证的代码的原因。至于如何“正确地”完成它(我慷慨地使用这个术语):


您还可以使用
val作为Foo
而不是
(Foo)val
如果你想在另一个类型中看到
null

无论如何,这是一件非常糟糕的事情;重叠引用是…嘎。为什么不只使用一个
对象
字段和两个属性来强制转换该字段呢?还有…可变结构、公共字段等;如果你确切知道你应该使用显式布局你正在做。它是为非托管互操作场景而设计的,而不是“胡闹”。看到了吗。什么是为胡闹而设计的?^^…我明白你的意思。我对动态关键字有点太兴奋了,我想我可以实现一些“私有访问”。
class Magic
{
    private object val;
    public ClassA InstanceA { get { return (InstanceA)val;} set { val = value; } }
    public ClassB InstanceB { get { return (InstanceB)val;} set { val = value; } }
}