标记这样的对象是合法代码吗?

Posted

技术标签:

【中文标题】标记这样的对象是合法代码吗?【英文标题】:Is it legit code to tag an object like this? 【发布时间】:2017-09-03 06:51:08 【问题描述】:

我曾经写过一篇code to add a name to a Task。下面的代码似乎做同样的事情,但代码更少。但我想知道,这是否合法。是否准备好生产代码。垃圾回收呢?在代码中移动的类的实例怎么样(因为它没有固定),它在移动时是否仍然有效?我该如何测试这段代码?

using System.Runtime.InteropServices;

namespace ConsoleApplication1

    class Program
    
        static void Main(string[] args)
        
            var obj = new object();
            obj.Tag("Link some data");
            var tag = obj.Tag();
        
    

    public static class ObjectExtensions
    
        private class Tagger
        
            public string Tag  get; set; 
        

        [StructLayout(LayoutKind.Explicit)]
        private struct Overlay
        
            [FieldOffset(0)]
            public Tagger Tagger;
            [FieldOffset(0)]
            public object Instance;
        

        public static string Tag(this object obj)
        
            var overlay = new Overlay Instance = obj ;
            return overlay.Tagger.Tag;
        

        public static void Tag(this object obj, string tag)
        
            var overlay = new Overlay Instance = obj ;
            overlay.Tagger.Tag = tag;
        
    

【问题讨论】:

【参考方案1】:

不,这根本不合法。坦率地说,我很惊讶 .NET 和 C# 在没有 /unsafe 开关的情况下允许这样做。您的建议有明显的风险,但我不得不承认,在使用 C# 编码的这些年中,我从来没有想过在 C# 中可以像这样违反安全内存访问,而无需显式启用不安全代码。

在您的示例中考虑这种变化:

class A

    public string Text  get; set; 


class Program

    static void Main(string[] args)
    
        A a = new A  Text = "Text" ;

        a.Tag("object A tag");

        string tag = a.Tag(), text = a.Text;
    

您会发现,在最后一条语句中,text 变量已设置为 "object A Tag"。换句话说,您的“覆盖”方法允许您的代码重新解释对 A 类对象的引用,作为对 Overlay 类对象的引用,而不会出现任何类型的编译器警告或运行时错误全部。

在上面的示例中,结果与您希望的一样好:Text 的原始属性值已从其正确值更改为作为“标签”传递的文本。这已经够糟糕的了,但在其他情况下,您可能会发现您的课程已经以可怕的方式损坏,导致进一步的数据损坏或(如果您幸运的话)由于某种访问冲突或其他异常导致您的程序立即终止.

不要这样做。这是非常危险的,而且当以您在此处提出的方式使用时,肯定不会永远正常工作。你总是会覆盖一些你不应该拥有的数据。

【讨论】:

今晚我花了一些时间研究这个问题,发现了一些有趣的事情:将Tagger 更改为结构似乎会强制CLR 将数据写入Overlay 对象的末尾struct 共享,所以那里没有明显的坏事发生。同样,如果原始对象是int[] 的数组并且int 被写入Tagger,则内存中从起始指针开始的 64 字节包含一些序列号(int[3] 的数组导致了这个数字从第一个 int 开始 +60),但如果写了其他任何内容,则该数字与第一个 int 相同...这真的很酷。

以上是关于标记这样的对象是合法代码吗?的主要内容,如果未能解决你的问题,请参考以下文章

C语言中一些“令人吃惊”的结构合法吗?

这是合法的模板 lambda 语法吗?

&errno 合法吗?

这是合法的引用可打印编码吗?

物格门牌是真的吗?物格门牌合法吗?

星图金融的银行存款合法吗星图金融的银行存款合法吗?