【问题标题】:FatalExecutionEngineError when messing with StructLayouts与 StructLayouts 混淆时出现 FatalExecutionEngineError
【发布时间】:2015-01-27 12:01:21
【问题描述】:

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

下面的代码按我想的那样工作:

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。

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

【问题讨论】:

  • 那是真的坏事反正;覆盖参考是...... gah。为什么不只拥有一个object 字段和两个转换该字段的属性?还有...可变结构、公共字段等;p
  • 只有在清楚知道自己在做什么的情况下才应该使用显式布局。它专为非托管互操作场景而设计,而不仅仅是“乱搞”。见stackoverflow.com/q/23323696/517852
  • 那么什么是为搞乱而设计的? ^^...我明白你在说什么。

标签: c# dynamic structlayout


【解决方案1】:

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

  • 通过假装一个非空类引用实际上是不同的类型(但这样做没有进行类型检查)
  • 通过让它尝试从int 加载object 引用(dynamic 只是object 带有一些花哨的编译器技巧)(注意;在所有情况下,这很可能指向垃圾;在x64 的情况下,它甚至不是一个完整的宽度,所以它会将垃圾读入要取消引用的值

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

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

如果您想在null 是其他类型时看到(Foo)val,也可以使用val as Foo 而不是(Foo)val

【讨论】:

  • 嗯,我对动态关键字有点太兴奋了,我想我可以做一些“私人访问”。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-03-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多