![](/img/trans.png)
[英]Why does my Lambda query return an anonymous type versus Linq's strongly-typed return value?
[英]Does casting an anonymous lambda to a strongly typed delegate disable compiler caching?
我試圖理解編譯器驅動的委托緩存的邊緣情況,以避免內存分配。
例如,根據我的理解,此委托被緩存到單個實例並重用,因為它不會關閉任何局部變量:
int[] set = new [] { 1, 2, 3, 4, 5, 6 };
var subset = set.Where(x => x % 2 == 0);
現在我遇到一些情況,我生成的代碼可能想直接調用委托,因此匿名方法無效C#,如下所示:
var result = (x => x % 2 == 0).Invoke(5); // Invalid
為了避免這種情況,我看到兩個選擇:
var result = (new Func<int, bool>(x => x % 2 == 0)).Invoke(5);
var result = ((Func<int, bool>)(x => x % 2 == 0)).Invoke(5);
我假設編譯器不會在選項#1中緩存委托,但我不確定它是否會在#2中。
這記錄在哪里?
我假設編譯器不會在選項#1中緩存委托,但我不確定它是否會在#2中。
事實上,它可以在兩種情況下,並且它們是捆綁在一起的。
從ECMA C#5規范,第7.6.10.5節:
新D(E)形式的委托創建表達式的綁定時處理,其中D是委托類型,E是表達式,包括以下步驟:
- ...
- 如果E是匿名函數,則委托創建表達式的處理方式與從E到D的匿名函數轉換(第6.5節)相同。
- ...
所以基本上兩者都以同樣的方式處理。 在這兩種情況下都可以緩存。 是的,“新的並不一定意味着新的”是非常奇怪的。
為了表明這一點,讓我們寫一個非常簡單的程序:
using System;
public class Program
{
public static void Main()
{
var func = new Func<int, bool>(x => x % 2 == 0);
}
}
這是我的機器上的Main
方法的IL(誠然使用C#8預覽編譯器構建,但我希望它會持續一段時間):
.method public hidebysig static void Main() cil managed
{
.entrypoint
// Code size 29 (0x1d)
.maxstack 8
IL_0000: ldsfld class [mscorlib]System.Func`2<int32,bool> Program/'<>c'::'<>9__0_0'
IL_0005: brtrue.s IL_001c
IL_0007: ldsfld class Program/'<>c' Program/'<>c'::'<>9'
IL_000c: ldftn instance bool Program/'<>c'::'<Main>b__0_0'(int32)
IL_0012: newobj instance void class [mscorlib]System.Func`2<int32,bool>::.ctor(object,
native int)
IL_0017: stsfld class [mscorlib]System.Func`2<int32,bool> Program/'<>c'::'<>9__0_0'
IL_001c: ret
} // end of method Program::Main
那是有效的:
Func<int, bool> func;
func = cache;
if (func == null)
{
func = new Func<int, bool>(GeneratedPrivateMethod);
cache = func;
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.