2010-01-07 37 views
8

Tôi có một truy vấn LINQ trông như thế này:Thay thế một phương pháp thông thường với một phương pháp vô danh trong C#/LINQ

public IEnumerable<Foo> SelectFooBars() 
{ 
    return 
     from 
      f in foos 
     join 
      b in bars 
      on f.BarId equals b.Id 
     select 
      AddMissingProp(f, b.MissingProp); 
} 

public void AddMissingProp(Foo foo, string missingProp) // substitute this with inline lambda 
{ 
    foo.MissingProp = missingProp; 
    return foo; 
} 

Tôi muốn thoát khỏi AddMissingProp và sử dụng một số hình thức của một lambda trong select của tôi thay vào đó.

Tôi đã cố gắng ...

... 
select 
    (f, b) => { f.MissingProp = b.MissingProp; return f } 

... nhưng tôi đã nhận được lỗi sau:

A local variable named 'f' cannot be declared in this scope because it would give a different meaning to 'f', which is already used in a 'parent or current' scope to denote something else.

Làm thế nào tôi có thể "lambda-ize" truy vấn của tôi?


Cập nhật

này cũng không hoạt động:

... 
select 
    () => { f.MissingProp = b.MissingProp; return f } 

tôi nhận được lỗi sau:

The type of one of the expressions in the join clause is incorrect. Type inference failed in the call to 'Join'.

tôi không thay đổi mệnh đề join tại tất cả, vì vậy tôi bối rối.

+1

Tôi không biết cú pháp LINQ đủ tốt để viết nó ra, nhưng nó sẽ không được tốt hơn làm các đột biến trong một tuyên bố foreach (yourLinqQuery)? Có một mutate chọn các đối tượng có vẻ khó hiểu. –

+0

thử * trên f.BarId bằng b.Id * –

+0

@Doc Brown, đó thực sự chỉ là lỗi đánh máy trong ví dụ của tôi (mã thực sự của tôi cho biết 'bằng’). Đã sửa lỗi. – devuxer

Trả lời

3

Bạn có thể cung cấp các loại cho tham số của mình trong biểu thức lambda nhưng bạn cần phải sử dụng các tên khác nhau vì bạn đã sử dụng f và b trong truy vấn.

(Foo f1, Bar b1) => ...

Sửa

return 
(
    from 
     f in foos 
    join 
     b in bars 
     on f.BarId equals b.Id 
    select 
     new {f, b} 
).select(foobar => {foobar.f.BarId = foobar.b.Id; return foobar.f}); 
+0

điều này cũng không hoạt động. –

+0

Điều này không hoạt động. Nó không biết rằng nó phải đi qua trong 'f' và' b'. Tôi cũng nhận được lỗi tương tự như khi tôi sử dụng '() => {...}' (xem cập nhật của tôi). – devuxer

+0

Xem chỉnh sửa của tôi, xin vui lòng ... –

1

chọn (f2, b2) => {f2.MissingProp = b2.MissingProp; return f2}

+0

điều này sẽ không hoạt động. –

+0

Điều này không hoạt động. Nó không biết rằng nó phải đi qua trong 'f' và' b'. Tôi cũng nhận được lỗi tương tự như khi tôi sử dụng() => {...} (xem cập nhật của tôi). – devuxer

1

Viết lại điều này bằng cú pháp Lambda.

var vf2 = foos.Join(bars, f => f.id, b => b.id, (foo, bar) => { foo.MissingProp = bar.MissingProp; return foo; }); 

Nếu bạn cần giải thích về cú pháp này, hãy cho tôi biết.

+0

Vì lý do nào đó, điều này gây ra lỗi với mệnh đề nối (mặc dù tôi không thay đổi mệnh đề nối): * Kiểu của một trong các biểu thức trong mệnh đề nối không chính xác. Loại suy luận thất bại trong cuộc gọi đến 'Tham gia'. * – devuxer

+0

thats bởi vì khi bạn chọn bạn đang nói cho nó kiểu trả về, chọn() giả sử bạn đang trả về kiểu ủy nhiệm. Tôi nghĩ bạn nên gắn bó với phương pháp của bạn. –

+0

Hmm ... có thể không thể thực hiện được. Nhưng tại sao nó không thể suy ra kiểu trả về từ 'return f;'? Nó biết f là một 'Foo'. – devuxer

5

Tôi nghĩ icambron là đúng, IMHO phiên bản có thể đọc được tốt hơn là thế này:

var fooBar = from 
       f in foos 
       join 
       b in bars 
       on f.BarId equals b.Id 
       select new {f,b}; 

    foreach(var x in fooBar) 
     x.f.MissingProp = x.b.MissingProp; 

    // EDIT due to comments: add this if you 
    // need IEnumerable<Foo> returned 
    return fooBar.Select(fb => fb.f); 

Các from join select báo cáo được cho các truy vấn, họ nên không được lạm dụng để biến đổi các nội dung của một chuỗi.

EDIT: Dưới đây là một số khác link cung cấp một số thông tin chi tiết về lý do sử dụng hình thức chức năng ForEach không phải là một ý tưởng hay.

+0

Cảm ơn +1. Tôi đã nghĩ về việc sử dụng 'foreach' nhưng tôi đoán tôi đã cố gắng quá ưa thích :) Đây là một giải pháp tốt. – devuxer

+0

Rất tiếc, một sự cố. Điều này khiến tôi có một 'IEnumerable ' nhưng tôi cần một 'IEnumerable '. Tôi nghĩ nếu bạn thêm 'return fooBar.Select (fb => fb.f);' vào câu trả lời của bạn, nó sẽ đúng. – devuxer

+2

Bạn cũng có thể thực hiện 'var foobar = (....). ForEach (....); 'và một dòng nó! –

1

Nếu trình biên dịch không thể suy ra đúng loại để chuyển đến một lambda, bạn tất nhiên có thể chỉ định loại chính mình.

này nên hoạt động tốt:

select 
    (Foo f2, b) => { f2.MissingProp = b.MissingProp; return f2; } 

Lưu ý rằng khi bạn đã nhận thấy, bạn không thể tái sử dụng f và hy vọng rằng nó sẽ giữ được ý nghĩa của nó.Đây là chữ ký phương thức mới, với các tham số mới, vì vậy bạn cần sử dụng tên riêng cho nó.

Khi thực hiện, bạn nhận thấy rằng trình biên dịch không thể tự tìm ra loại đối số đầu tiên, nhưng bạn có thể chỉ định đối số, như trên.

+0

Đối với mã không đầy đủ, tôi đã quên câu lệnh return của mình. Chỉ cần sửa nó. – devuxer

+0

Bạn cũng đã bỏ lỡ dấu chấm phẩy cuối cùng sau truy vấn LINQ. Bạn nên luôn cố gắng sao chép và dán những gì bạn có trong mã của bạn, không cố gắng đơn giản hóa nó. Bạn sẽ ngạc nhiên trước những gì mọi người ở đây có thể đọc được mã số: –

+0

đã xóa phần cuối của câu trả lời để phản ánh câu hỏi đã chỉnh sửa. –

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