![](/img/trans.png)
[英]C# Custom generic struct with same compiler behavior as Nullable<T>
[英]Is it possible to cheat C# compiler to box Nullable<T> struct ant not its value?
嗯,问题可能看起来很奇怪。 它确实是。
然而,我坚信这些黑客有助于理解语言和.net平台。
C#编译器如何处理可空类型意味着这个问题。
Nullable<T>
是一个结构。 但编译器框不是这个结构,而是它保存的值或只是空引用。
在盒装Nullable的情况下,拆箱将如何工作也很有用。
Nullable<int> myInt = boxedStruct as Nullable<int>;
在这里我认为boxedStruct
不是一个盒装的int而是整个结构。
好吧,可能是在CLR级别对Nullables的处理方式不同,因为我无法理解下面程序的ouptut。
class Program
{
public static bool? Property { get; set; }
static void Main(string[] args)
{
Property = true;
var valueType = typeof (Program).GetProperty("Property").GetValue(null).GetType();
var propType = typeof (Program).GetProperty("Property").PropertyType;
Console.WriteLine("Value's type '{0}' is the same as type of the property '{1}' - '{2}'", valueType, propType, valueType == propType);
Console.ReadKey();
}
}
输出:
值的类型'System.Boolean'与属性'System.Nullable`1 [System.Boolean]'的类型相同 - ''False'
更新:
这里的规范(ECMA 335)说:
I.8.2.4值的装箱和拆箱
...
如果值类型是可空类型 - 定义为值类型System.Nullable的实例化 - 结果是其类型为T的Value属性的空引用或按位副本,具体取决于其HasValue属性(分别为false和true) 。
所以如果我理解正确的话。 Nulllable Nullable<T>
strcut不能装入.Net Framework中,它不仅不可能用C#编译器,而且用CLR也是如此。
我猜想你要问的问题是:
你可以
Nullable<int>
值而不产生空引用或盒装int值,而是实际装箱的Nullable<int>
吗?
没有。
有可能欺骗C#编译器来装箱
Nullable<T>
吗?
不,因为不是编辑谁做拳击,它是CLR。 是的,可空类型的装箱是在CLR本身中专门处理的。
那么有没有办法在没有这种特殊处理的情况下装入可以为空的结构? 也没有。
但是可以打包另一个看起来像Nullable<T>
(确保它具有适当的布局),并且在未记录的关键字和内存黑客的帮助下,让CLR认为盒装对象实际上是Nullable<T>
。
谨防! 此代码仅用于教育目的。 我不能保证它可以在其他平台上工作或在不同条件下工作,因为它依赖于托管对象的底层布局。
public static unsafe object BoxNullable<T>(T? nullable) where T : struct
{
object scam = new NullableFake<T>(nullable);
TypedReference tr = __makeref(scam);
IntPtr typehandle = typeof(Nullable<T>).TypeHandle.Value;
IntPtr* trstruct = (IntPtr*)&tr;
**((IntPtr**)trstruct[0]) = typehandle;
return scam;
}
struct NullableFake<T> where T : struct
{
public readonly T? Value;
public NullableContainer(T? nullable)
{
Value = nullable;
}
}
所述NullableFake<T>
结构具有的布局相同Nullable<T>
所以它是安全的使用它的拳击。 TypedReference
用于获取指向变量的指针(包含指向对象的指针),从而暴露对象本身。 对象内存布局中的第一个值是指向对象类型的指针。 覆盖它会导致CLR认为类型不同。
我不知道有任何更安全的方法。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.