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



我曾经写过一段代码来为任务添加名称。下面的代码似乎也做了同样的事情,但代码更少。但我想知道,这合法吗?它是否准备好生产代码。垃圾回收呢?在代码中移动类的实例(因为它没有固定)怎么办,当它被移动时它仍然有效吗?如何测试此代码?

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

不,这根本不合法。坦率地说,我很惊讶 .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的原始属性值已从其正确值更改为作为"标记"传递的文本。这已经够糟糕的了,但在其他情况下,你可能会发现你的类已经以可怕的方式被破坏,导致进一步的数据损坏,或者(如果你幸运的话)由于某种访问违规或其他异常而导致程序立即终止。

别这样。这是非常危险的,当然,当以您在此处建议的方式使用时,将永远无法正常工作。您将始终覆盖一些不应该拥有的数据。

相关内容

  • 没有找到相关文章

最新更新