C# 给定;其中T:new();,是不是;新的T();是否在内部使用Activator.CreateInstance?
如果我有一个类型参数约束C# 给定;其中T:new();,是不是;新的T();是否在内部使用Activator.CreateInstance?,c#,generics,reflection,activator,type-constraints,C#,Generics,Reflection,Activator,Type Constraints,如果我有一个类型参数约束new(): void Foo(),其中T:new() { var t=新的t(); } new T()是否会在内部使用Activator.CreateInstance方法(即反射)?是。它对引用类型有效 在以下版本编译代码上使用ILSpy: public static void DoWork<T>() where T: new() { T t = new T(); Console.WriteLine(t.To
new()
:
void Foo(),其中T:new()
{
var t=新的t();
}
new T()
是否会在内部使用Activator.CreateInstance
方法(即反射)?是。它对引用类型有效
在以下版本编译代码上使用ILSpy:
public static void DoWork<T>() where T: new()
{
T t = new T();
Console.WriteLine(t.ToString());
}
publicstaticvoiddowork(),其中T:new()
{
T=新的T();
Console.WriteLine(t.ToString());
}
屈服
.method public hidebysig
instance void DoWork<.ctor T> () cil managed
{
// Method begins at RVA 0x2064
// Code size 52 (0x34)
.maxstack 2
.locals init (
[0] !!T t,
[1] !!T CS$0$0000,
[2] !!T CS$0$0001
)
IL_0000: ldloca.s CS$0$0000
IL_0002: initobj !!T
IL_0008: ldloc.1
IL_0009: box !!T
IL_000e: brfalse.s IL_001b
IL_0010: ldloca.s CS$0$0001
IL_0012: initobj !!T
IL_0018: ldloc.2
IL_0019: br.s IL_0020
IL_001b: call !!0 [mscorlib]System.Activator::CreateInstance<!!T>()
IL_0020: stloc.0
IL_0021: ldloca.s t
IL_0023: constrained. !!T
IL_0029: callvirt instance string [mscorlib]System.Object::ToString()
IL_002e: call void [mscorlib]System.Console::WriteLine(string)
IL_0033: ret
} // end of method Program::DoWork
.method公共隐藏
实例void DoWork()cil托管
{
//方法从RVA 0x2064开始
//代码大小52(0x34)
.maxstack 2
.init(
[0]!!T T,
[1] !!T CS$0$0000,
[2] !!T CS$0$0001
)
IL_0000:ldloca.s$0$0000
IL_0002:initobj!!T
IL_0008:ldloc.1
IL_0009:box!!T
IL_000e:brfalse.s IL_001b
IL_0010:ldloca.s CS$0$0001
IL_0012:initobj!!T
IL_0018:ldloc.2
IL_0019:br.s IL_0020
IL_001b:call!!0[mscorlib]System.Activator::CreateInstance()
IL_0020:stloc.0
IL_0021:ldloca.s t
IL_0023:受约束。!!T
IL_0029:callvirt实例字符串[mscorlib]System.Object::ToString()
IL_002e:调用void[mscorlib]System.Console::WriteLine(字符串)
IL_0033:ret
}//方法结束程序::DoWork
或者在C#中:
public void DoWork(),其中T:new()
{
T=(默认值(T)=null)?Activator.CreateInstance():默认值(T);
Console.WriteLine(t.ToString());
}
JIT将为传入的每个不同的值类型参数创建不同的编译指令,但对引用类型使用相同的指令——因此Activator.CreateInstance()是的,这是正确的编辑2:这里有一个很好的解释,说明了如何以及为什么 为了验证,我编译了以下方法:
public static T Create<T>() where T: new() {
return new T();
}
publicstatict Create(),其中T:new(){
返回新的T();
}
这是使用.NET 3.5 SP1中的C#编译器编译时生成的IL:
.method public hidebysig static !!T Create<.ctor T>() cil managed
{
.maxstack 2
.locals init (
[0] !!T local,
[1] !!T local2)
L_0000: ldloca.s local
L_0002: initobj !!T
L_0008: ldloc.0
L_0009: box !!T
L_000e: brfalse.s L_001a
L_0010: ldloca.s local2
L_0012: initobj !!T
L_0018: ldloc.1
L_0019: ret
L_001a: call !!0 [mscorlib]System.Activator::CreateInstance<!!T>()
L_001f: ret
}
.method公共隐藏静态!!T Create()cil管理
{
.maxstack 2
.init(
[0]!!T本地,
[1] !!T local2)
L_0000:ldloca.s本地
L_0002:initobj!!T
L_0008:ldloc.0
L_0009:box!!T
L_000e:brfalse.s L_001a
L_0010:ldloca.s local2
L_0012:initobj!!T
L_0018:ldloc.1
L_0019:ret
L_001a:call!!0[mscorlib]System.Activator::CreateInstance()
L_001f:ret
}
编辑:C#4编译器创建的代码略有不同,但相似:
.method public hidebysig static !!T Create<.ctor T>() cil managed
{
.maxstack 2
.locals init (
[0] !!T CS$1$0000,
[1] !!T CS$0$0001)
L_0000: nop
L_0001: ldloca.s CS$0$0001
L_0003: initobj !!T
L_0009: ldloc.1
L_000a: box !!T
L_000f: brfalse.s L_001c
L_0011: ldloca.s CS$0$0001
L_0013: initobj !!T
L_0019: ldloc.1
L_001a: br.s L_0021
L_001c: call !!0 [mscorlib]System.Activator::CreateInstance<!!T>()
L_0021: stloc.0
L_0022: br.s L_0024
L_0024: ldloc.0
L_0025: ret
}
.method公共隐藏静态!!T Create()cil管理
{
.maxstack 2
.init(
[0]!!T CS$1$0000,
[1] !!T CS$0$0001)
L_0000:没有
L_0001:ldloca.s CS$0$0001
L_0003:initobj!!T
L_0009:ldloc.1
L_000a:盒子!!T
L_000f:brfalse.s L_001c
L_0011:ldloca.s CS$0$0001
L_0013:initobj!!T
L_0019:ldloc.1
L_001a:br.s L_0021
L_001c:call!!0[mscorlib]System.Activator::CreateInstance()
L_0021:stloc.0
L_0022:br.s L_0024
L_0024:ldloc.0
L_0025:ret
}
对于值类型,它不使用activator,只返回
默认(t)
值,否则它调用activator.CreateInstance
方法。@Oded如果您试图更好地理解正在编程的环境,那么是的-这很重要!:-)@克拉根:伊尔达斯姆,monodis@seheIL Spy是我目前选择的反编译器-我参与并反编译Microsoft程序集(尝试回答类似问题)的时候实际上非常有启发性,并对我的编码风格产生了相当大的影响。请注意,随着Roslyn的出现,这种行为发生了变化。如果添加了struct
约束,则先前未调用Activator.CreateInstance
。今天,不管约束如何,IL都将调用Activator.CreateInstance
。非常相似的q:@Jason:initobj
被定义为“将指定地址处值类型的每个字段初始化为空引用或相应基元类型的0。。。与Newobj不同,initobj不调用构造函数方法。Initobj用于初始化值类型,而newobj用于分配和初始化对象。“没有迹象表明它调用引用类型的默认构造函数。我假设它相当于default(T)
@CodeInChaos:我已经删除了我的评论。我犯了一个错误。好吧,那么最大的问题是为什么。为什么编译器不发出一条newobj
指令?那么如果约束是类,new()
?它仍然使用激活器-我假设是因为newobj
的预期标记是构造函数标记,而不是类型标记。对于“值类型”也是如此。请参阅本书第544页/第11章-C#编程语言-第三版
。
.method public hidebysig static !!T Create<.ctor T>() cil managed
{
.maxstack 2
.locals init (
[0] !!T local,
[1] !!T local2)
L_0000: ldloca.s local
L_0002: initobj !!T
L_0008: ldloc.0
L_0009: box !!T
L_000e: brfalse.s L_001a
L_0010: ldloca.s local2
L_0012: initobj !!T
L_0018: ldloc.1
L_0019: ret
L_001a: call !!0 [mscorlib]System.Activator::CreateInstance<!!T>()
L_001f: ret
}
.method public hidebysig static !!T Create<.ctor T>() cil managed
{
.maxstack 2
.locals init (
[0] !!T CS$1$0000,
[1] !!T CS$0$0001)
L_0000: nop
L_0001: ldloca.s CS$0$0001
L_0003: initobj !!T
L_0009: ldloc.1
L_000a: box !!T
L_000f: brfalse.s L_001c
L_0011: ldloca.s CS$0$0001
L_0013: initobj !!T
L_0019: ldloc.1
L_001a: br.s L_0021
L_001c: call !!0 [mscorlib]System.Activator::CreateInstance<!!T>()
L_0021: stloc.0
L_0022: br.s L_0024
L_0024: ldloc.0
L_0025: ret
}