像这样标记对象是合法代码吗?
Is it legit code to tag an object like this?
我曾经写过一篇code to add a name to a Task。下面的代码似乎做同样的事情,但代码更少。但我想知道,这是合法的。生产代码准备好了吗?垃圾回收呢? class 的实例在代码中四处移动(因为它没有被固定)怎么样,当它四处移动时它仍然有效吗?如何测试此代码?
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"
。换句话说,您的 "overlay" 方法允许您的代码将对 class A
对象的引用重新解释为对 class [=15= 对象的引用], 没有任何类型的编译器警告或 运行-time 错误。
在上面的示例中,结果与您希望的一样好:Text
的原始 属性 值已从其正确值更改为作为 "tag"。这已经够糟糕了,但在其他情况下,您可能会发现您的 class 已以可怕的方式损坏,导致进一步的数据损坏或(如果您幸运的话)由于某种访问而导致您的程序立即终止违规或其他异常。
不要这样做。这是非常危险的,当然,当按照您在此处建议的方式使用时,永远不会 正常工作。你总是会覆盖一些你不应该拥有的数据。
我曾经写过一篇code to add a name to a Task。下面的代码似乎做同样的事情,但代码更少。但我想知道,这是合法的。生产代码准备好了吗?垃圾回收呢? class 的实例在代码中四处移动(因为它没有被固定)怎么样,当它四处移动时它仍然有效吗?如何测试此代码?
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"
。换句话说,您的 "overlay" 方法允许您的代码将对 class A
对象的引用重新解释为对 class [=15= 对象的引用], 没有任何类型的编译器警告或 运行-time 错误。
在上面的示例中,结果与您希望的一样好:Text
的原始 属性 值已从其正确值更改为作为 "tag"。这已经够糟糕了,但在其他情况下,您可能会发现您的 class 已以可怕的方式损坏,导致进一步的数据损坏或(如果您幸运的话)由于某种访问而导致您的程序立即终止违规或其他异常。
不要这样做。这是非常危险的,当然,当按照您在此处建议的方式使用时,永远不会 正常工作。你总是会覆盖一些你不应该拥有的数据。