2008-09-12 29 views
21

Tôi mới sử dụng tất cả các tính năng ẩn danh và cần trợ giúp. Tôi đã nhận được những điều sau đây để làm việc:Chuyển đổi đại biểu này sang một phương thức ẩn danh hoặc lambda

public void FakeSaveWithMessage(Transaction t) 
{ 
    t.Message = "I drink goats blood"; 
} 

public delegate void FakeSave(Transaction t); 

public void SampleTestFunction() 
{ 
    Expect.Call(delegate { _dao.Save(t); }).Do(new FakeSave(FakeSaveWithMessage)); 
} 

Nhưng điều này hoàn toàn xấu và tôi muốn có bên trong của Do là một phương pháp ẩn danh hoặc thậm chí là lambda nếu có thể. Tôi cố gắng:

Expect.Call(delegate { _dao.Save(t); }).Do(delegate(Transaction t2) { t2.Message = "I drink goats blood"; }); 

Expect.Call(delegate { _dao.Save(t); }).Do(delegate { t.Message = "I drink goats blood"; }); 

nhưng cho tôi

Không thể chuyển đổi phương pháp vô danh để gõ 'System.Delegate' vì nó không phải là một loại đại biểu ** biên dịch lỗi .

Tôi đang làm gì sai?


Bởi vì những gì Mark Ingram được đăng, có vẻ như câu trả lời tốt nhất, mặc dù không ai nói nó một cách rõ ràng, là để làm điều này:

public delegate void FakeSave(Transaction t); 

Expect.Call(delegate { _dao.Save(t); }).Do(new FakeSave(delegate(Transaction t2) { t.Message = expected_msg; })); 

Trả lời

27

Đó là thông báo lỗi nổi tiếng. Kiểm tra liên kết dưới đây để có một cuộc thảo luận chi tiết hơn.

http://staceyw1.wordpress.com/2007/12/22/they-are-anonymous-methods-not-anonymous-delegates/

Về cơ bản bạn chỉ cần đặt một dàn diễn viên trước đại biểu vô danh của bạn (biểu thức lambda của bạn).

Trong trường hợp liên kết bao giờ đi xuống, đây là một bản sao của bài:

Họ là Anonymous phương pháp, không Anonymous Các đại biểu.
Được đăng trên 22 tháng 12 năm 2007 bởi staceyw1

Nó không chỉ là một điểm nói vì chúng tôi muốn trở nên khó khăn. Nó giúp chúng tôi lý do chính xác về những gì đang diễn ra. Để rõ ràng, có * không có điều như vậy làm đại biểu ẩn danh. Chúng không tồn tại (chưa). Họ là "Anonymous Phương pháp" - khoảng thời gian. Nó quan trọng trong cách , chúng tôi nghĩ về chúng và cách chúng ta nói về số chúng.Hãy xem câu hỏi về phương thức ẩn danh "delegate() {...}". Đây thực sự là hai hoạt động khác nhau và khi chúng ta nghĩ về nó theo cách này, chúng ta sẽ không bao giờ bị nhầm lẫn nữa. Điều đầu tiên mà trình biên dịch thực hiện là tạo phương thức ẩn danh bên dưới bìa bằng cách sử dụng ký hiệu đại diện được phỏng đoán làm phương thức chữ ký. Không đúng khi nói phương thức là "không được đặt tên" vì nó không có tên và trình biên dịch gán nó. Nó chỉ bị ẩn khỏi chế độ xem thông thường. Điều tiếp theo nó là tạo đối tượng ủy nhiệm của loại yêu cầu để bọc phương thức. Điều này được gọi là suy luận của đại biểu và có thể là nguồn gốc của sự nhầm lẫn này. Để điều này hoạt động, trình biên dịch phải là có thể tìm ra (ví dụ: suy luận) những gì loại đại biểu mà nó sẽ tạo. Nó có là loại bê tông đã biết. Hãy để viết một số mã để xem lý do.

private void MyMethod() 
{ 
} 

Không biên dịch:

1) Delegate d = delegate() { };      // Cannot convert anonymous method to type ‘System.Delegate’ because it is not a delegate type 
2) Delegate d2 = MyMethod;       // Cannot convert method group ‘MyMethod’ to non-delegate type ‘System.Delegate’ 
3) Delegate d3 = (WaitCallback)MyMethod; // No overload for ‘MyMethod’ matches delegate ‘System.Threading.WaitCallback’ 

Line 1 không biên dịch bởi vì trình biên dịch không thể suy ra bất kỳ đại biểu loại. Nó có thể thấy rõ ràng chữ ký mà chúng ta mong muốn, nhưng không có loại cụ thể nào mà trình biên dịch có thể thấy. Nó có thể tạo một loại vô danh của loại đại biểu cho chúng tôi, nhưng nó không hoạt động như thế. Dòng 2 không biên dịch vì một lý do tương tự. Thậm chí mặc dù trình biên dịch biết chữ ký , chúng tôi không cho nó một loại đại diện và nó không chỉ là để chọn một tác vụ có thể làm việc (không phải tác dụng phụ nào có thể ). Dòng 3 không hoạt động vì chúng tôi cố tình không khớp với phương pháp chữ ký với đại biểu có chữ ký khác nhau (như WaitCallback mất và đối tượng).

biên dịch:

4) Delegate d4 = (MethodInvoker)MyMethod; // Works because we cast to a delegate type of the same signature. 
5) Delegate d5 = (Action)delegate { };    // Works for same reason as d4. 
6) Action d6 = MyMethod;        // Delegate inference at work here. New Action delegate is created and assigned. 

Ngược lại, những công việc. Dòng 1 hoạt động vì chúng tôi thông báo cho trình biên dịch loại loại đại biểu nào để sử dụng và chúng khớp với, để nó hoạt động. Dòng 5 hoạt động cho cùng một lý do. Lưu ý rằng chúng tôi đã sử dụng hình thức đặc biệt của "ủy quyền" mà không có giấy phép. Trình biên dịch đưa vào phương thức chữ ký từ dàn diễn viên và tạo ra phương thức ẩn danh với cùng một chữ ký làm đại biểu được suy ra loại. Dòng 6 hoạt động vì MyMethod() và Hành động sử dụng cùng một chữ ký .

Tôi hy vọng điều này sẽ hữu ích.

Xem thêm: http://msdn.microsoft.com/msdnmag/issues/04/05/C20/

+1

Tốt liên kết, nhưng tôi vẫn không hiểu tại sao * * trình biên dịch không cast nó Automagically (như nó với cú pháp lambda) –

+0

Liên kết bị hỏng. –

+0

Vẫn đang làm việc cho tôi? –

0

Hãy thử một cái gì đó như:

Expect.Call(delegate { _dao.Save(t); }).Do(new EventHandler(delegate(Transaction t2) { t2.CheckInInfo.CheckInMessage = "I drink goats blood"; })); 

Note EventHandler được thêm vào xung quanh đại biểu.

EDIT: có thể không hoạt động vì chữ ký chức năng của EventHandler và đại biểu không giống nhau ... Giải pháp bạn thêm vào cuối câu hỏi có thể là cách duy nhất.

Cách khác, bạn có thể tạo ra một loại đại biểu chung chung:

public delegate void UnitTestingDelegate<T>(T thing); 

Vì vậy mà các đại biểu không phải là giao dịch cụ thể.

3

gì Mark nói.

Vấn đề là Do thực hiện tham số Delegate. Trình biên dịch không thể chuyển đổi các phương thức ẩn danh thành Đại biểu, chỉ có một "loại đại biểu" tức là một loại cụ thể có nguồn gốc từ Đại biểu.

Nếu chức năng Do đó đã thực hiện hành động <>, Hành động <,> ... quá tải, bạn sẽ không cần truyền.

1

Vấn đề không phải với định nghĩa đại biểu của bạn, đó là tham số của phương thức Do() thuộc loại System.Delegate và trình biên dịch tạo ra loại đại biểu (FakeSave) không chuyển đổi hoàn toàn sang System.Delegate.

Hãy thử thêm một dàn diễn viên trước đại biểu vô danh của bạn:

Expect.Call(delegate { _dao.Save(t); }).Do((Delegate)delegate { t.Message = "I drink goats blood"; }); 
+0

Điều này không làm việc ủy ​​nhiệm {} là một chức năng vô danh - nó không phải là một loại. System.Delegate là lớp cơ sở trừu tượng là cơ sở ngầm của tất cả các loại ủy nhiệm được khai báo. Có 3 cách sử dụng khác nhau của từ đại biểu ở đây! Bạn có thể downcast bất kỳ loại đại biểu nào (ví dụ như EvantHandler, Action, Func ) thành Delegate nhưng trước tiên bạn phải tạo một loại đại biểu! –

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