1

私はstructlayoutsをいじっていて、かなり奇妙なものを見つけました:

次のコードは、思ったとおりに機能しています。

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

基本的に、あなたがしたことは完全に未定義です。あなたは2つの非常に厄介な方法でそれをだましています:

  • 1 つの非 null クラス参照が実際には異なる型であると偽ることによって (ただし、これは型チェックなしで行われます)
  • object参照をロードしようとすることによって(いくつかの派手なコンパイラのトリックを使用するdynamicだけです) (注; すべての場合、これはほとんどの場合、ガベージを指します; x64 の場合、幅全体でさえないため、逆参照する値にガベージを読み込みますobjectint

基本的に:そうしないでください。これは偶然にも、明示的なレイアウトが検証不可能なコードとして扱われる理由です。それを「適切に」行う方法については(そして私はその用語を惜しみなく使用しています):

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 に答える