2012-10-13 34 views
13

Trong đoạn mã này:Tại sao lambdas có thể chuyển đổi các cuộc gọi chức năng thành Hành động?

List<String> names = new List<String>(); 
names.Add("Bruce"); 
names.Add("Tom"); 
names.Add("Tim"); 
names.Add("Richard"); 

names.ForEach(x => Print(x)); 

private static string Print(string s) 
{ 
    Console.WriteLine(s); 
    return s; 
} 

Print không phải là một Action chắc chắn vì nó đang trở lại string; tuy nhiên x=> Print(x) là, tại sao?

+3

Vui lòng cải thiện tiêu đề của câu hỏi này. Google sử dụng nó để đặt tiêu đề cho kết quả tìm kiếm của nó và tiêu đề của bạn hoàn toàn không phải là Googlable. –

Trả lời

16

Loại biểu thức lambda x => Print(x) được xác định dựa trên ngữ cảnh của nó. Vì trình biên dịch biết rằng lambda được gán cho Action<string>, trình biên dịch bỏ qua kiểu trả về của phương thức Print(s) như thể nó là một biểu thức câu lệnh .

Đây là một chuyển đổi hợp lệ:

Action<string> myAction = y => Print(y); 

Nói cách khác, cả hai

Print("something"); 

int x = Print("something"); 

những tập quán chính xác của các phương pháp Print; chúng có thể được sử dụng trong lambdas theo cách tương tự.

+0

Vì chuỗi trả về In, tại sao trình biên dịch có thể lấy kiểu trả về là void và khớp với Hành động? –

+4

Bởi vì một điều hợp pháp để làm với chuỗi là ném nó đi. Bạn không cần phải nói rõ rằng bạn đang vứt bỏ một giá trị trả về - không sử dụng nó là đủ. –

+0

Trong thực tế, hầu như mỗi lần bạn gán một biến, bạn đang làm điều tương tự, vì biểu thức gán trả về giá trị đã gán! Vì vậy, một hành động chỉ định một raible đang làm điều tương tự. –

9

x => Print(x) là một lambda được biến thành một phương pháp ở đây tương đương với:

void MyPrintLambda(string x) { Print(x); } 

Nếu bối cảnh đã kêu gọi, nói rằng, một Func<string, string>, nó đã có này:

string MyPrintLambda(string x) { return Print(x); } 

Hoặc nếu đó là số Func<string, object>, nó sẽ là:

object MyPrintLambda(string x) { return Print(x); } 

Bởi vì trình biên dịch có thể biến x => Print(x) thành một Action<string> bằng cách bỏ qua kiểu trả về (tức là ví dụ đầu tiên), nó có thể biên dịch.

+1

Bit cuối cùng không hoàn toàn chính xác, 'names.ForEach (Print)' sẽ không biên dịch, vì 'Print' KHÔNG chuyển đổi thành' Action ',' x => Print (x) ', tuy nhiên, vì biểu thức 'các loại được định nghĩa dựa trên cách sử dụng – mlorbetske

+0

@mlorbetske bạn nói đúng, tôi đã xóa bit đó ngay bây giờ. –

4

Đối với cùng một lý do rằng điều này sẽ có giá trị:

foreach (string name in names) 
{ 
    Print(name); 
} 

Phương pháp In() trả về một giá trị trong mã đó là tốt, nhưng không ai có thể mong đợi điều này là một lỗi. Nó được phép chỉ vứt bỏ giá trị trả về.

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