2012-10-24 17 views
6

Tôi bằng cách nào đó cảm thấy tôi thiếu một cái gì đó cơ bản. Đây là vấn đề của tôi.Tạo một tác vụ với một hành động <T>

Tôi đang cố gắng tạo một phiên bản System.Threading.Tasks.Task để thực thi hành động chấp nhận tham số của một loại nhất định. Tôi nghĩ tôi có thể làm điều gì đó như

void DoWork(MyClass obj) {} //My action that accepts a parameter of type 'MyClass' 

MyClass obj = new MyClass(); 
Action<MyClass> action = DoWork; //action that points to the method 
Task task = new Task(action,obj); //task that would execute 'DoWork' with 'obj' as the parameter when I call Start. 

Rõ ràng điều này không biên dịch. Có vẻ như tôi chỉ có thể sử dụng một số Action<object> và không phải là Action<T> cho một tác vụ và sau đó truyền 'đối tượng' vào T bên trong phương thức của tôi.

Làm cách nào để đạt được những gì tôi muốn một cách hiệu quả và hiệu quả nhất?

Trả lời

4

Bạn có thể sử dụng

Action<Object> action = o => DoWork((MyClass)o); 
Task task = new Task(action, obj); 

Nếu bạn đang sử dụng .NET 4.0 trở lên, bạn có thể sử dụng Contravariance để đạt được mục tiêu của mình mà không giới thiệu một đại biểu mới

 
//INCORRECT Code, casts InvalidCastException at runtime 
Action action = DoWork; 
Task task = new Task((Action)action, obj); 

EDI T:

Cảm ơn vì @svick đã chỉ ra rằng tùy chọn thứ hai không chính xác: Tôi quá bận phân loại, cho dù Hành động có đồng nhất hay contravariant (thực tế là contravariant, tôi đã đúng về điều này tại ít nhất) mà tôi giám sát, rằng tôi sẽ cần Hiệp phương sai trong trường hợp này.

Contravariance có nghĩa là bạn có thể làm

Action<object> action1 = someAction; 
Action<SubClass> action2 = action1; 

mà không đúc rõ ràng.

+0

Bất kỳ lý do tại sao điều này không phải là một phần của API? – alwayslearning

+0

'Nhiệm vụ' nằm trong khuôn khổ kể từ .Net 4.0, vì vậy tôi nghĩ rằng vòng loại là không cần thiết. – svick

+0

Ngoài ra, đó không phải là cách hoạt động của contravariance, bạn có thể truyền 'Action ' sang 'Hành động ', nhưng không phải là cách khác. – svick

4

Bạn cũng có thể sử dụng trực tiếp:

MyClass obj = new MyClass(); 
Task task = Task.Run(() => DoWork(obj)); 
+0

Chỉ cần đề cập: Điều này có ý nghĩa hơi khác. Nếu bạn thay đổi * biến * 'obj' trước khi bắt đầu nhiệm vụ, hoặc thậm chí ngay trước logic' Task' được gọi là delegate, 'DoWork' sẽ làm việc trên đối tượng mới. Điều này có thể dẫn đến các lỗi rất khó theo dõi. Một tình huống cổ điển sẽ là, nếu bạn sử dụng điều này bên trong một vòng lặp foreach (MyClass o trong myObjList) {(new Task (() => DoWork (o))). } '. – MartinStettner

+0

@MartinStettner, _ "Một tình huống cổ điển sẽ là, nếu bạn sử dụng điều này bên trong một vòng lặp" _ foreach vòng lặp đã được thay đổi và bây giờ mã như vậy là chính xác. – Qwertiy

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