gpt4 book ai didi

C#泛型是盒装的?

转载 作者:可可西里 更新时间:2023-11-01 07:46:00 28 4
gpt4 key购买 nike

我执行了以下代码:

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

我在 Main 函数中有两个局部变量,它们是 name 和 age。我正在使用 console.writeline 方法打印它们。它打印没有任何问题。 main方法的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

我有另一个通用类“GClass”。在通用类中,我有两个属性和一个方法(显示)。在 Display 方法中,我显示这两个属性的方式与在 Main 方法中显示局部变量的方式相同。 Generic Class Display方法的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

我将“string”作为类型参数传递给 T1 并使用此类型声明 Name 属性。当使用 Console.Writeline 显示名称属性时,它会将名称装箱 (IL_000c: box !T1)。你可以在 IL 中找到它。

明明是字符串类型,为什么还要装箱?

最佳答案

之所以这样,是因为编译器不确定 T1T2 是否始终是引用类型或值类型。所以当 T1 或 T2 是值类型或引用类型时,默认情况下将它们放入 Object 中。

Object 类型可以对偶。当它是引用类型时,它可以对值类型进行装箱和拆箱,并且保存对任何子类实例的引用类型。

所以当 T1 是字符串时,它实际上不是装箱,它持有字符串实例的引用,因为 Object 是字符串类型的基类,实际上是任何 .Net 类型。

如果 T2 是 int,它就是简单的装箱-拆箱。

关于C#泛型是盒装的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3298040/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com