1

我把结构布局弄乱了,我发现了一些我觉得很奇怪的东西:

以下代码按我的想法工作:

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。

谁能解释为什么或者如何解决?我知道这可能太复杂了,我只是在这里捣乱,但有人可能想要一些挑战。

4

1 回答 1

0

基本上,您所做的事情是完全未定义的。您以两种非常讨厌的方式欺骗​​它:

  • 通过假装一个非空类引用实际上是一种不同的类型(但是这样做没有类型检查)
  • 通过让它尝试从object(注意;在所有情况下,这很可能指向垃圾;在 x64 的情况下,它甚至不是整个宽度,所以它会将垃圾读要取消引用的值dynamicobjectint

基本上:不要那样做。这就是为什么显式布局被视为无法验证的代码的原因。至于如何“正确”地做到这一点(我慷慨地使用了这个词):

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; } }
}

如果您想查看它何时是其他类型,您也可以使用val as Foo而不是。(Foo)valnull

于 2014-11-28T20:39:58.550 回答