2013-08-06 32 views
5

Yêu cầu sau có được tự động "tối ưu hóa" không?Sử dụng tối ưu nhất cho nhiều câu lệnh Where

var result = initial 
       .Where(Predicate1) 
       .Where(Predicate2) 
       .Where(Predicate3); 

này tương đương với

var result = initial 
       .Where(e => Predicate1(e) && Predicate2(e) && Predicate3(e)); 

Mà một trong các báo cáo được càng tối ưu hóa của hai? Hay chúng giống hệt nhau?

+0

Ý của bạn là gì? Điều này không đúng trong quan điểm của tôi .. –

+0

Không, điều này không xảy ra. Vấn đề thực tế bạn đang cố gắng giải quyết là gì? –

+0

@Soner: "sạch", hiệu quả hơn. – Toto

Trả lời

8

Mặc dù mã được biên dịch không kết hợp các biến vị ngữ, thực thi thực chất là không. Phương thức where của Linq trả về một WhereListIterator khi thông qua một List. Các WhereListIterator có riêng của mình nơi phương pháp thực hiện mà trả về một mớiListListterator với các vị từ kết hợp. Nó trông giống như thế này:

return new Enumerable.WhereListIterator<T>(this.source, Enumerable.CombinePredicates<T>(this.predicate, predicate)

nơi this.source là List, this.predicate là vị đầu tiên ở đâu, và vị ngữ là từ thứ hai đâu.

Các CombinePredicates trả về một đại biểu có chứa đoạn mã sau:

if (predicate1(source)) return predicate2(source); 
return false; 

Vì vậy, các xích đâu khoản nên kết thúc với một cái gì đó như:

if (predicate1(source)) { 
    if (predicate2(source) { 
     return predicate3(source) { 
    } 
    return false; 
} 
return false; 

Với một danh sách nhỏ, sử dụng & & để kết hợp các biến vị ngữ trong một đơn Vị trí có khả năng hiệu quả hơn, nhưng khi kích thước danh sách tăng thời gian chạy của hai tùy chọn có thể trở nên tương tự. Bạn sẽ phải cấu hình nó để định lượng chỉ là sự khác biệt là gì. Tôi nghi ngờ nó không đủ lớn để quan trọng.

+0

Điều đó khá thú vị. –

+1

Câu trả lời hay! Chỉ cần kiểm tra việc thực hiện 'Enumerable.Where' và bạn đã đúng! Luôn luôn có thời gian để tìm hiểu một cái gì đó mới. – MarcinJuraszek

6

Không, không phải. Các cuộc gọi phương thức Where này không được kết hợp thành một.

C# code:

var input = new List<string>(); 

var output = input.Where(x => x.StartsWith("test")).Where(x => x.Length > 10).Where(x => !x.EndsWith("test")); 

IL tạo:

IL_0000: newobj instance void class [mscorlib]System.Collections.Generic.List`1<string>::.ctor() 
IL_0005: stloc.0 
IL_0006: ldloc.0 
IL_0007: ldsfld class [mscorlib]System.Func`2<string, bool> ConsoleApplication2.Program::'CS$<>9__CachedAnonymousMethodDelegate3' 
IL_000c: brtrue.s IL_001f 

IL_000e: ldnull 
IL_000f: ldftn bool ConsoleApplication2.Program::'<Main>b__0'(string) 
IL_0015: newobj instance void class [mscorlib]System.Func`2<string, bool>::.ctor(object, native int) 
IL_001a: stsfld class [mscorlib]System.Func`2<string, bool> ConsoleApplication2.Program::'CS$<>9__CachedAnonymousMethodDelegate3' 

IL_001f: ldsfld class [mscorlib]System.Func`2<string, bool> ConsoleApplication2.Program::'CS$<>9__CachedAnonymousMethodDelegate3' 
IL_0024: call class [mscorlib]System.Collections.Generic.IEnumerable`1<!!0> [System.Core]System.Linq.Enumerable::Where<string>(class [mscorlib]System.Collections.Generic.IEnumerable`1<!!0>, class [mscorlib]System.Func`2<!!0, bool>) 
IL_0029: ldsfld class [mscorlib]System.Func`2<string, bool> ConsoleApplication2.Program::'CS$<>9__CachedAnonymousMethodDelegate4' 
IL_002e: brtrue.s IL_0041 

IL_0030: ldnull 
IL_0031: ldftn bool ConsoleApplication2.Program::'<Main>b__1'(string) 
IL_0037: newobj instance void class [mscorlib]System.Func`2<string, bool>::.ctor(object, native int) 
IL_003c: stsfld class [mscorlib]System.Func`2<string, bool> ConsoleApplication2.Program::'CS$<>9__CachedAnonymousMethodDelegate4' 

IL_0041: ldsfld class [mscorlib]System.Func`2<string, bool> ConsoleApplication2.Program::'CS$<>9__CachedAnonymousMethodDelegate4' 
IL_0046: call class [mscorlib]System.Collections.Generic.IEnumerable`1<!!0> [System.Core]System.Linq.Enumerable::Where<string>(class [mscorlib]System.Collections.Generic.IEnumerable`1<!!0>, class [mscorlib]System.Func`2<!!0, bool>) 
IL_004b: ldsfld class [mscorlib]System.Func`2<string, bool> ConsoleApplication2.Program::'CS$<>9__CachedAnonymousMethodDelegate5' 
IL_0050: brtrue.s IL_0063 

IL_0052: ldnull 
IL_0053: ldftn bool ConsoleApplication2.Program::'<Main>b__2'(string) 
IL_0059: newobj instance void class [mscorlib]System.Func`2<string, bool>::.ctor(object, native int) 
IL_005e: stsfld class [mscorlib]System.Func`2<string, bool> ConsoleApplication2.Program::'CS$<>9__CachedAnonymousMethodDelegate5' 

IL_0063: ldsfld class [mscorlib]System.Func`2<string, bool> ConsoleApplication2.Program::'CS$<>9__CachedAnonymousMethodDelegate5' 
IL_0068: call class [mscorlib]System.Collections.Generic.IEnumerable`1<!!0> [System.Core]System.Linq.Enumerable::Where<string>(class [mscorlib]System.Collections.Generic.IEnumerable`1<!!0>, class [mscorlib]System.Func`2<!!0, bool>) 
IL_006d: pop 
IL_006e: ret 

Như bạn có thể thấy, có 3 System.Linq.Enumerable::Where<string> cuộc gọi.

+0

Mặc dù tôi tin rằng nó có hiệu quả tương tự như xa như đánh giá ngắn mạch. – JosephHirn

+0

@Ginosaji Vâng, đó là như nhau, nhưng trình biên dịch không tối ưu hóa điều đó. Bạn phải làm điều đó một mình. – MarcinJuraszek

Các vấn đề liên quan