C#泛型类型是否已装箱?
我执行了以下代码:C#泛型类型是否已装箱?,c#,.net,C#,.net,我执行了以下代码: using System; using System.Collections.Generic; namespace TestReleaseAndDebug { public class GClass<T1, T2> { public T1 Name { get; set; } public T2 Age { get; set; } public void Display()
using System;
using System.Collections.Generic;
namespace TestReleaseAndDebug
{
public class GClass<T1, T2>
{
public T1 Name { get; set; }
public T2 Age { get; set; }
public void Display()
{
Console.WriteLine("Name: " + Name);
Console.WriteLine("Age: " + Age);
}
}
class Program
{
static void Main(string[] args)
{
GClass<string, int> person = new GClass<string, int>();
person.Name = "RAM";
person.Age = 34;
string name = "RAM";
int age = 34;
Console.WriteLine("Name: " + name);
Console.WriteLine("Age: " + age);
person.Display();
Console.Read();
}
}
}
使用系统;
使用System.Collections.Generic;
命名空间TestReleaseAndDebug
{
公共类GClass
{
公共T1名称{get;set;}
公共T2年龄{get;set;}
公共空间显示()
{
Console.WriteLine(“名称:”+名称);
控制台。WriteLine(“年龄:+Age”);
}
}
班级计划
{
静态void Main(字符串[]参数)
{
GClass person=新的GClass();
person.Name=“RAM”;
人,年龄=34岁;
string name=“RAM”;
年龄=34岁;
Console.WriteLine(“名称:”+名称);
控制台。WriteLine(“年龄:+Age”);
person.Display();
Console.Read();
}
}
}
我在主函数中有两个局部变量,它们是name和age。我正在使用console.writeline方法打印它们。它打印出来没有任何问题。主要方法的IL如下所示:
.method private hidebysig static void Main(string[] args) cil managed
{
.entrypoint
// Code size 90 (0x5a)
.maxstack 2
.locals init ([0] class TestReleaseAndDebug.GClass`2<string,int32> person,
[1] string name,
[2] int32 age)
IL_0000: nop
IL_0001: newobj instance void class TestReleaseAndDebug.GClass`2<string,int32>::.ctor()
IL_0006: stloc.0
IL_0007: ldloc.0
IL_0008: ldstr "RAM"
IL_000d: callvirt instance void class TestReleaseAndDebug.GClass`2<string,int32>::set_Name(!0)
IL_0012: nop
IL_0013: ldloc.0
IL_0014: ldc.i4.s 34
IL_0016: callvirt instance void class TestReleaseAndDebug.GClass`2<string,int32>::set_Age(!1)
IL_001b: nop
IL_001c: ldstr "RAM"
IL_0021: stloc.1
IL_0022: ldc.i4.s 34
IL_0024: stloc.2
IL_0025: ldstr "Name: "
IL_002a: ldloc.1
IL_002b: call string [mscorlib]System.String::Concat(string,
string)
IL_0030: call void [mscorlib]System.Console::WriteLine(string)
IL_0035: nop
IL_0036: ldstr "Age: "
IL_003b: ldloc.2
IL_003c: box [mscorlib]System.Int32
IL_0041: call string [mscorlib]System.String::Concat(object,
object)
IL_0046: call void [mscorlib]System.Console::WriteLine(string)
IL_004b: nop
IL_004c: ldloc.0
IL_004d: callvirt instance void class TestReleaseAndDebug.GClass`2<string,int32>::Display()
IL_0052: nop
IL_0053: call int32 [mscorlib]System.Console::Read()
IL_0058: pop
IL_0059: ret
} // end of method Program::Main
.method private隐藏静态void Main(字符串[]args)cil托管
{
.入口点
//代码大小90(0x5a)
.maxstack 2
.locals init([0]类TestReleaseAndDebug.GClass`2个人,
[1] 字符串名,
[2] int32(年龄)
IL_0000:没有
IL_0001:newobj实例无效类TestReleaseAndDebug.GClass`2::.ctor()
IL_0006:stloc.0
IL_0007:ldloc.0
IL_0008:ldstr“RAM”
IL_000d:callvirt实例无效类TestReleaseAndDebug.GClass`2::set_Name(!0)
IL_0012:没有
IL_0013:ldloc.0
IL_0014:ldc.i4.s 34
IL_0016:callvirt实例无效类TestReleaseAndDebug.GClass`2::set_Age(!1)
IL_001b:没有
IL_001c:ldstr“RAM”
IL_0021:stloc.1
IL_0022:ldc.i4.s 34
IL_0024:stloc.2
IL_0025:ldstr“名称:”
IL_002a:ldloc.1
IL_002b:call string[mscorlib]System.string::Concat(string,
(字符串)
IL_0030:调用void[mscorlib]System.Console::WriteLine(字符串)
IL_0035:没有
IL_0036:ldstr“年龄:
IL_003b:ldloc.2
IL_003c:box[mscorlib]System.Int32
IL_0041:调用字符串[mscorlib]System.string::Concat(对象,
(对象)
IL_0046:调用void[mscorlib]System.Console::WriteLine(字符串)
IL_004b:没有
IL_004c:ldloc.0
IL_004d:callvirt实例void类TestReleaseAndDebug.GClass`2::Display()
IL_0052:没有
IL_0053:调用int32[mscorlib]System.Console::Read()
IL_0058:流行音乐
IL_0059:ret
}//方法程序结束::Main
我有另一个通用类“GClass”。在泛型类中,我有两个属性和一个方法(Display)。在Display方法中,我显示这两个属性的方式与我在Main方法中显示局部变量的方式相同。通用类显示方法的IL如下所示:
.method public hidebysig instance void Display() cil managed
{
// Code size 56 (0x38)
.maxstack 8
IL_0000: nop
IL_0001: ldstr "Name: "
IL_0006: ldarg.0
IL_0007: call instance !0 class TestReleaseAndDebug.GClass`2<!T1,!T2>::get_Name()
IL_000c: box !T1
IL_0011: call string [mscorlib]System.String::Concat(object,
object)
IL_0016: call void [mscorlib]System.Console::WriteLine(string)
IL_001b: nop
IL_001c: ldstr "Age: "
IL_0021: ldarg.0
IL_0022: call instance !1 class TestReleaseAndDebug.GClass`2<!T1,!T2>::get_Age()
IL_0027: box !T2
IL_002c: call string [mscorlib]System.String::Concat(object,
object)
IL_0031: call void [mscorlib]System.Console::WriteLine(string)
IL_0036: nop
IL_0037: ret
} // end of method GClass`2::Display
.method public hidebysing instance void Display()cil managed
{
//代码大小56(0x38)
.maxstack 8
IL_0000:没有
IL_0001:ldstr“名称:”
IL_0006:ldarg.0
IL_0007:调用实例!0类TestReleaseAndDebug.GClass`2::get_Name()
IL_000c:box!T1
IL_0011:调用字符串[mscorlib]System.string::Concat(对象,
(对象)
IL_0016:调用void[mscorlib]System.Console::WriteLine(字符串)
IL_001b:没有
IL_001c:ldstr“年龄:
IL_0021:ldarg.0
IL_0022:调用实例!1类TestReleaseAndDebug.GClass`2::get_Age()
IL_0027:box!T2
IL_002c:调用字符串[mscorlib]System.string::Concat(对象,
(对象)
IL_0031:调用void[mscorlib]System.Console::WriteLine(字符串)
IL_0036:没有
IL_0037:ret
}//方法GClass`2::Display的结尾
我将“string”作为类型参数传递给T1,并使用此类型声明Name属性。当使用Console.Writeline显示Name属性时,它正在装箱名称(IL_000c:box!T1)。你可以在IL找到这个
为什么拳击是一种弦式拳击 编译器必须生成可以跨所有泛型类型工作的IL。编译器无法知道您总是使用
安装GCClass
。它必须处理T1
是一种值类型的可能性
但是,我希望引用类型上的box
是禁止操作的。JIT从Display
方法的IL为引用和值类型生成不同的机器代码。对于引用类型,我希望删除框
指令
如果您确定
T1
永远不会是一个值类型,您可以向其添加:class
约束,这将删除框
指令。这太了,因为编译器不确定T1
和T2
始终都是引用类型或值类型。因此,对于T1或T2这两种情况,默认情况下都会将它们放入Object中,无论它们是值类型还是引用类型
类型对象
可以在二元性中起作用。它可以为值类型取消装箱,并且在引用类型为任何子类时保留对其实例的引用
所以,如果T1是string,它实际上不是装箱,而是保存string实例的引用,因为Object是string类型的基类,实际上是任何.Net类型
如果T2为int,则是简单的装箱拆箱。查看
在第三部分第4.1节中,关于框
说明:
如果typeTok是值类型,则框
指令将val转换为其装箱的值
形式。当typeTok是不可为空的
类型(§1.8.2.4),这由
创建一个