如果做決定從Task
或Task<TResult>
繼承,你可能會遇到挫折的Action<Object>
或Func<Object,TResult>
委託,它提供了必須指定當時的任務,實際工作中的任務派生對象被構造,並且以後不能更改。即使基類構造函數不是新創建的任務,也是如此,事實上,它可能很晚纔會啓動,如果有的話。
這使得在需要創建實例之前需要創建實例的情況下,很難使用Task
派生類,因爲實例必須在其最終工作的完整詳細信息可用之前創建。
一個例子可能是在一個共同的目標工作衆所周知Task<TResult>
節點的無定形網絡,使得它們訪問在特設方式彼此的Result
屬性。確保網絡中任意節點上可以使用Wait()
的最簡單方法是在啓動它們之前預先構建所有節點。這很好地避免了嘗試分析工作圖相關性的問題,並且允許運行時因素確定何時,如何以及以何種順序要求值。
這裏的問題是,對於某些節點,您可能不能夠提供定義在施工時工作中的作用。如果創建必要的lambda函數需要從網絡中的其他任務結束了Result
數值,提供我們想要的Result
的Task<TResult>
可能尚未建立呢。即使它恰好是在施工前階段早期構建的,您也不能在其上調用Start()
,因爲它可能會將依賴關係併入其他沒有的節點。請記住,構建網絡的關鍵在於避免這些複雜性。
如果這還不夠,還有其他的原因是不方便,要使用lambda功能提供所需的功能。因爲它傳遞到構造函數作爲參數,函數不能訪問this
指針最終任務實例,這使得醜陋的代碼,特別是考慮的範圍之內必然定義的拉姆達 - 可能無意關閉過 - 一些不相關的this
指針。
我可以繼續下去,但底線是,你不應該在派生類中定義的擴展功能時要忍受運行關閉膨脹等的麻煩。這不會錯過多態性的全部點嗎?以正常的方式定義一個Task
派生類的工作委託,即基類中的一個抽象函數會更加優雅。
這裏是如何做到這一點。訣竅是定義一個私有構造函數,它關閉其自己的一個參數。最初設置爲null
的參數充當佔位符變量,您可以關閉它以創建基類Task
所需的代理。一旦你在構造函數體中,'this'指針可用,所以你可以修補實際的函數指針。
對於從 '任務' 導出:
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();
};
對於從 '任務<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();
};
[編輯:簡化]
這些簡化版本通過直接關閉派生實例'動作或函數方法直接關閉來進一步減少無關閉包。這也可以釋放基類中的AsyncState
以防您想要使用它。由於你現在擁有了你自己的完整的派生類,所以幾乎沒有必要。因此,AsyncState
未傳遞到工作函數中。如果你需要它,你總是可以從基類的屬性中抓取它。最後,現在可以將各種可選參數傳遞給基類Task
。
對於從 '任務' 導出:
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();
};
對於從 '任務<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();
};
感謝您的'Task.AsyncState'我沒有意識到它。我只關心它爲什麼反對?有人可以覆蓋它。 – 2012-02-13 18:10:04
@MikeChaliy它旨在實現IAsyncResult,並且是隻讀的。一旦你構建你的任務,任何人都無法在你身上覆蓋它。你需要使用'採取行動
@ReedCopsey UPS,是的,你是對的。那麼,看起來更好。 – 2012-02-13 18:16:34