如果我内联一个 HashSet 集合初始化,编译器是否知道只执行一次?
If I inline a HashSet collection initialization, does the compiler know to do it only once?
我经常这样做...
private void Check()
{
string s = "blah";
if ( new HashSet<string>{"Joe","Eddie","Buckethead"}.Contains(s) )
Debug.Log("Guitarist.");
}
pipeline中,HashSet是否真的只创建一次(启动时?编译时?)然后每次都使用?
顺便说一句,我假设如果你这样做:
private HashSet<string> g = new HashSet<string>()
{"Joe","Eddie","Buckethead"};
private void Check()
{
string s = "blah";
if ( g.Contains(s) )
Debug.Log("Guitarist.");
}
那么确实,当然只在实例化Class的时候做一次。 (或者,也许在编译时/启动时?但无论如何,只有一次。)
new
将在运行时恰好在线程到达该行的时间点创建新对象。
因此对于第一个代码段,每次调用 Check
方法都会导致创建一个新的 HashSet
对象。
在第二种情况下,每次构造包含 class 的新实例时都会创建一个新的 HashSet
对象。
这个代码
{
string s = "blah";
if ( new HashSet<string>{"Joe","Eddie","Buckethead"}.Contains(s) )
Debug.Log("Guitarist.");
}
总是实例化一个新的 HashSet<string>
。
顺便说一句,新对象一旦不再被引用就可用,在本例中是在您关闭后 }
。
你说得对,当 class 初始化时,将其作为 class 实例字段将初始化一次。在这种情况下,您可以使用 readonly
关键字来防止 class 在对象初始化后更改初始值。如果您有一个永远不会更改的昂贵初始化并且可能有许多 class 实例,您可以将该字段标记为 static
以便 HashSet<string>
的单个实例在所有对象实例之间共享.
hmm .. ok but compilers know to only make once other literals, right? (eg, "strings" etc)
常量不会产生任何初始化开销。编译器可以在适当的地方使用文字值。
默认string literals are interned (see also),这意味着给定字符串的内存只会分配一次。
这是第一个方法的 IL:
Check:
IL_0000: ldstr "blah"
IL_0005: stloc.0 // s
IL_0006: newobj System.Collections.Generic.HashSet..ctor
IL_000B: dup
IL_000C: ldstr "Joe"
IL_0011: callvirt System.Collections.Generic.HashSet.Add
IL_0016: pop
IL_0017: dup
IL_0018: ldstr "Eddie"
IL_001D: callvirt System.Collections.Generic.HashSet.Add
IL_0022: pop
IL_0023: dup
IL_0024: ldstr "Buckethead"
IL_0029: callvirt System.Collections.Generic.HashSet.Add
IL_002E: pop
IL_002F: ldloc.0 // s
IL_0030: callvirt System.Collections.Generic.HashSet.Contains
IL_0035: brfalse.s IL_0041
IL_0037: ldstr "Guitarist."
IL_003C: call System.Console.WriteLine
IL_0041: ret
这是第二种方法的代码:
Check:
IL_0000: ldstr "blah"
IL_0005: stloc.0 // s
IL_0006: ldarg.0
IL_0007: ldfld g
IL_000C: ldloc.0 // s
IL_000D: callvirt System.Collections.Generic.HashSet.Contains
IL_0012: brfalse.s IL_001E
IL_0014: ldstr "Guitarist."
IL_0019: call System.Console.WriteLine
IL_001E: ret
这就是代码的优化编译。
所以,是的,第一个每次都会创建一个新的 HashSet
。
哦,我将 Debug.Log
更改为 Console.WriteLine
,但这是一个微不足道的更改。
我经常这样做...
private void Check()
{
string s = "blah";
if ( new HashSet<string>{"Joe","Eddie","Buckethead"}.Contains(s) )
Debug.Log("Guitarist.");
}
pipeline中,HashSet是否真的只创建一次(启动时?编译时?)然后每次都使用?
顺便说一句,我假设如果你这样做:
private HashSet<string> g = new HashSet<string>()
{"Joe","Eddie","Buckethead"};
private void Check()
{
string s = "blah";
if ( g.Contains(s) )
Debug.Log("Guitarist.");
}
那么确实,当然只在实例化Class的时候做一次。 (或者,也许在编译时/启动时?但无论如何,只有一次。)
new
将在运行时恰好在线程到达该行的时间点创建新对象。
因此对于第一个代码段,每次调用 Check
方法都会导致创建一个新的 HashSet
对象。
在第二种情况下,每次构造包含 class 的新实例时都会创建一个新的 HashSet
对象。
这个代码
{
string s = "blah";
if ( new HashSet<string>{"Joe","Eddie","Buckethead"}.Contains(s) )
Debug.Log("Guitarist.");
}
总是实例化一个新的 HashSet<string>
。
顺便说一句,新对象一旦不再被引用就可用,在本例中是在您关闭后 }
。
你说得对,当 class 初始化时,将其作为 class 实例字段将初始化一次。在这种情况下,您可以使用 readonly
关键字来防止 class 在对象初始化后更改初始值。如果您有一个永远不会更改的昂贵初始化并且可能有许多 class 实例,您可以将该字段标记为 static
以便 HashSet<string>
的单个实例在所有对象实例之间共享.
hmm .. ok but compilers know to only make once other literals, right? (eg, "strings" etc)
常量不会产生任何初始化开销。编译器可以在适当的地方使用文字值。
默认string literals are interned (see also),这意味着给定字符串的内存只会分配一次。
这是第一个方法的 IL:
Check: IL_0000: ldstr "blah" IL_0005: stloc.0 // s IL_0006: newobj System.Collections.Generic.HashSet..ctor IL_000B: dup IL_000C: ldstr "Joe" IL_0011: callvirt System.Collections.Generic.HashSet.Add IL_0016: pop IL_0017: dup IL_0018: ldstr "Eddie" IL_001D: callvirt System.Collections.Generic.HashSet.Add IL_0022: pop IL_0023: dup IL_0024: ldstr "Buckethead" IL_0029: callvirt System.Collections.Generic.HashSet.Add IL_002E: pop IL_002F: ldloc.0 // s IL_0030: callvirt System.Collections.Generic.HashSet.Contains IL_0035: brfalse.s IL_0041 IL_0037: ldstr "Guitarist." IL_003C: call System.Console.WriteLine IL_0041: ret
这是第二种方法的代码:
Check: IL_0000: ldstr "blah" IL_0005: stloc.0 // s IL_0006: ldarg.0 IL_0007: ldfld g IL_000C: ldloc.0 // s IL_000D: callvirt System.Collections.Generic.HashSet.Contains IL_0012: brfalse.s IL_001E IL_0014: ldstr "Guitarist." IL_0019: call System.Console.WriteLine IL_001E: ret
这就是代码的优化编译。
所以,是的,第一个每次都会创建一个新的 HashSet
。
哦,我将 Debug.Log
更改为 Console.WriteLine
,但这是一个微不足道的更改。