我刚刚在another question上回答了以下LINQ查询,它返回了某些字符串组合的列表:
public static List<String> Combis(string value)
{
var combis =
from bool1 in new bool[] {true, false}
from bool2 in new bool[] {true, false}
let i1 = 1
let i2 = 1
from i3 in new int[] {10, 20, 30}
select value + "_" + bool1 + "_" + bool2 + "_" + i1 + "_" + i2 + "_" + i3;
return combis.ToList();
}
我现在问自己:每个子句(例如,... in new bool[] {true, false}
)只被评估过一次或多次,即,每个子句中是否只有一个多个创建的数组?
更新
如答案所示,它被多次评估。我会将代码更改为
public static List<String> Combis(string value)
{
bool[] bools = new[] {true, false};
int[] ints = new[] {10, 20, 30};
var combis =
from bool1 in bools
from bool2 in bools
let i1 = 1
let i2 = 1
from i3 in ints
select value + "_" + bool1 + "_" + bool2 + "_" + i1 + "_" + i2 + "_" + i3;
return combis.ToList();
}
因此不必创建多个数组。
答案 0 :(得分:1)
多次评估。查询表达式具有指定的方法调用转换。我使用Resharper来执行转换。避开你的眼睛......
new bool[] { true, false }
.SelectMany(bool1 => new bool[] { true, false }, (bool1, bool2) => new { bool1, bool2 })
.Select(@t => new { @t, i1 = 1 })
.Select(@t => new { @t, i2 = 1 })
.SelectMany(@t => new int[] { 10, 20, 30 }, (@t, i3) => "" + "_" + @t.@t.@t.bool1 + "_" + @t.@t.@t.bool2 + "_" + @t.@t.i1 + "_" + @t.i2 + "_" + i3);
对于每个bool1
,正在创建一个新数组。
它真的不能是任何其他方式。如果您写了以下内容怎么办?
from bool1 in new [] { true, false }
from bool2 in new [] { bool1 } //dependent on bool1!
可以根据范围内的所有范围变量生成内部序列。这是动态的。
但是,C#编译器可以优化它吗?它不能,因为不允许知道Enumerable.SelectMany
不依赖于传入的序列的对象标识。例如,它可以将每个哈希代码打印到控制台。
答案 1 :(得分:1)
可以按如下方式测试(LINQPad的代码):
void Main()
{
Combis("");
}
private static bool[] Test(string arg)
{
Console.WriteLine("!{0}", arg);
return new bool[] {true, false};
}
public static List<String> Combis(string value)
{
var combis =
from bool1 in Test("A")
from bool2 in Test("B")
let i1 = 1
let i2 = 1
from i3 in new int[] {10, 20, 30}
select value + "_" + bool1 + "_" + bool2 + "_" + i1 + "_" + i2 + "_" + i3;
return combis.ToList();
}
输出:
!A
!B
!B
您可以看到Test("A")
被调用一次,Test("B")
被调用了两次。
我们也可以考虑int数组:
void Main()
{
Combis("");
}
private static bool[] TestBool(string arg)
{
Console.WriteLine("!{0}", arg);
return new bool[] {true, false};
}
private static int[] TestInt(string arg)
{
Console.WriteLine("!{0}", arg);
return new int[] {10, 20, 30};
}
public static List<String> Combis(string value)
{
var combis =
from bool1 in TestBool("A")
from bool2 in TestBool("B")
let i1 = 1
let i2 = 1
from i3 in TestInt("C")
select value + "_" + bool1 + "_" + bool2 + "_" + i1 + "_" + i2 + "_" + i3;
return combis.ToList();
}
输出:
!A
!B
!C
!C
!B
!C
!C
我们发现每次调用TestInt("C")
(其中有两个)后,TestBool("A")
被调用两次,总共四次。
正确更新问题中显示的数组初始化将阻止双重初始化。