Vấn đề ở đây là, đối với một số nút, bạn có thể không thể cung cấp chức năng xác định công việc tại thời điểm xây dựng. Nếu việc tạo hàm lambda cần thiết yêu cầu đóng trên Result
giá trị từ các tác vụ khác trong mạng, thì Task<TResult>
cung cấp Result
chúng tôi muốn có thể chưa được tạo. Và ngay cả khi nó xảy ra đã được xây dựng trước đó trong giai đoạn tiền xây dựng, bạn không thể gọi Start()
trên nó vì nó có thể kết hợp phụ thuộc vào các nút khác mà không có. Hãy nhớ rằng, toàn bộ điểm xây dựng trước mạng là để tránh những phức tạp như thế này.
Như thể điều này không đủ, có nhiều lý do khác khiến việc sử dụng hàm lambda không thuận tiện để cung cấp chức năng mong muốn. Bởi vì nó được truyền vào hàm khởi tạo như một đối số, hàm không thể truy cập con trỏ this
của cá thể tác vụ cuối cùng, làm cho mã xấu xí, đặc biệt là xem xét lambda nhất thiết được xác định trong phạm vi - và có thể vô tình đóng -some không liên quan đến con trỏ this
.
Tôi có thể tiếp tục, nhưng điểm mấu chốt là bạn không cần phải chịu đựng bloat đóng cửa thời gian chạy và các phức tạp khác khi xác định chức năng mở rộng trong lớp dẫn xuất. Điều đó không bỏ lỡ toàn bộ điểm đa hình? Nó sẽ là thanh lịch hơn để xác định các đại biểu công việc của một lớp học Task
-derived theo cách thông thường, cụ thể là, một hàm trừu tượng trong lớp cơ sở.
Dưới đây là cách thực hiện. Bí quyết là định nghĩa một hàm tạo riêng tư để đóng một trong các đối số của chính nó. Đối số, ban đầu được đặt thành null
, hoạt động như một biến giữ chỗ mà bạn có thể đóng để tạo đại biểu theo yêu cầu của lớp cơ sở Task
. Khi bạn đang ở trong phần thân của hàm tạo, con trỏ 'this' có sẵn, vì vậy bạn có thể vá trong con trỏ hàm thực tế.
Đối với phát sinh từ 'Nhiệm vụ':
public abstract class DeferredActionTask : Task
{
private DeferredActionTask(DeferredActionTask _this)
: base(_ => ((Func<DeferredActionTask>)_)().action(),
(Func<DeferredActionTask>)(() => _this))
{
_this = this;
}
protected DeferredActionTask() : this(null) { }
protected abstract void action();
};
Đối với phát sinh từ 'Task <TResult>':
public abstract class DeferredFunctionTask<TResult> : Task<TResult>
{
private DeferredFunctionTask(DeferredFunctionTask<TResult> _this)
: base(_ => ((Func<DeferredFunctionTask<TResult>>)_)().function(),
(Func<DeferredFunctionTask<TResult>>)(() => _this))
{
_this = this;
}
protected DeferredFunctionTask() : this(null) { }
protected abstract TResult function();
};
[Edit: Giản]
Các phiên bản được đơn giản hóa này tiếp tục giảm các bao đóng không liên quan bằng cách đóng trực tiếp trên các thể hiện bắt buộc 'hành động hoặc chức năng phương pháp'. Điều này cũng giải phóng các AsyncState
trong lớp cơ sở trong trường hợp bạn muốn sử dụng nó. Nó hầu như không cần thiết vì bạn có toàn bộ lớp học có nguồn gốc riêng của bạn ngay bây giờ; theo đó, AsyncState
không được chuyển vào chức năng làm việc. Nếu bạn cần nó, bạn luôn có thể lấy nó từ tài sản trên lớp cơ sở. Cuối cùng, các tham số tùy chọn khác nhau có thể được chuyển qua lớp cơ sở Task
.
Đối với phát sinh từ 'Nhiệm vụ':
public abstract class DeferredActionTask : Task
{
private DeferredActionTask(Action _a, Object state, CancellationToken ct, TaskCreationOptions opts)
: base(_ => _a(), state, ct, opts)
{
_a = this.action;
}
protected DeferredActionTask(
Object state = null,
CancellationToken ct = default(CancellationToken),
TaskCreationOptions opts = TaskCreationOptions.None)
: this(default(Action), state, ct, opts)
{
}
protected abstract void action();
};
Đối với phát sinh từ 'Task <TResult>':
public abstract class DeferredFunctionTask<TResult> : Task<TResult>
{
private DeferredFunctionTask(Func<TResult> _f, Object state, CancellationToken ct, TaskCreationOptions opts)
: base(_ => _f(), state, ct, opts)
{
_f = this.function;
}
protected DeferredFunctionTask(
Object state = null,
CancellationToken ct = default(CancellationToken),
TaskCreationOptions opts = TaskCreationOptions.None)
: this(default(Func<TResult>), state, ct, opts)
{
}
protected abstract TResult function();
};
Cảm ơn 'Task.AsyncState' Tôi không biết về nó. Tôi chỉ quan tâm là tại sao nó phản đối? Ai đó có thể ghi đè lên nó. –
@MikeChaliy Nó được thiết kế để triển khai IAsyncResult và chỉ đọc. Không ai có thể ghi đè lên bạn khi bạn xây dựng nhiệm vụ của mình. Bạn cần phải xây dựng Nhiệm vụ bằng cách sử dụng một trong các hàm tạo có 'Hành động
@ReedCopsey up, vâng, bạn nói đúng. Vâng, trông đẹp hơn sau đó. –