【问题标题】: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# 也是一种解决实际编程问题的非常实用的语言。现实世界并不纯粹。

标签: c# inheritance struct structlayout


【解决方案1】:

好吧,你告诉 CLR 使用 StructLayout 提前布置内存(我应该提醒一下,这是基于我今天在实验和阅读其他建议的答案后的学习

您可以在这里看出 CLR 实际上并没有实例化任何东西。这将引发 NPE。您可以在 super 上使用构造函数。它没有被调用,也不会。

基本上你是在直接访问内存,因为stringint 等都是内置类型,你可以安全地与它们交互。这可能需要用户更多的“意图”,而其他评论的问题都指向这需要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; }
}

【讨论】:

    猜你喜欢
    • 2011-06-09
    • 1970-01-01
    • 2015-02-12
    • 2021-11-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多