标记这样的对象是合法代码吗?
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 相同...这真的很酷。以上是关于标记这样的对象是合法代码吗?的主要内容,如果未能解决你的问题,请参考以下文章