El problema aquí es que, para algunos de los nodos, es posible que no pueda proporcionar la función que define el trabajo en tiempo de construcción. Si la creación de la función lambda necesaria requiere el cierre de Result
valores de otras tareas en la red, el Task<TResult>
que proporciona el Result
que queremos podría no haberse construido aún. Y aunque se haya construido anteriormente durante la fase de preconstrucción, no puede llamar al Start()
, ya que podría incorporar dependencias en otros nodos que no lo hayan hecho. Recuerde, el objetivo de preconstruir la red fue evitar complejidades como estas.
Como si esto fuera poco, hay otras razones por las que no es conveniente tener que usar una función lambda para proporcionar la función deseada. Dado que se transfiere al constructor como argumento, la función no puede acceder al puntero this
de la instancia de tarea eventual, lo que crea un código feo, especialmente si se considera que la lambda se define necesariamente bajo el alcance de, y posiblemente sobre el cierre inadvertido. -algunos punteros this
no relacionados.
Podría seguir, pero la conclusión es que no debería tener que soportar la saturación del cierre del tiempo de ejecución y otras molestias al definir la funcionalidad extendida en una clase derivada. ¿No pierde eso el punto del polimorfismo? Sería más elegante definir el delegado de trabajo de una clase derivada de Task
de la manera normal, es decir, una función abstracta en la clase base.
He aquí cómo hacerlo. El truco consiste en definir un constructor privado que cierra uno de sus propios argumentos. El argumento, inicialmente establecido en null
, actúa como una variable de marcador de posición que puede cerrar para crear el delegado requerido por la clase base Task
. Una vez que estás en el cuerpo del constructor, el puntero 'this' está disponible, por lo que puedes aplicar un parche al puntero de la función real.
Para derivado de 'tarea':
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();
};
Para derivado de 'Tarea <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();
};
[Editar: simplificado]
Estas versiones simplificadas reducen aún más cierres extraños cerrando directamente sobre los casos derivados acción o función método. Esto también libera el AsyncState
en la clase base en caso de que quiera usarlo. Difícilmente parece necesario ya que ahora tiene su propia clase derivada completa; en consecuencia, AsyncState
no se pasa a la función de trabajo. Si lo necesita, siempre puede tomarlo de la propiedad en la clase base. Finalmente, los diversos parámetros opcionales ahora se pueden pasar a la clase base Task
.
Para que deriva de 'tarea':
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();
};
Para que deriva de 'tareas <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();
};
Gracias por 'Task.AsyncState' Yo no estaba al tanto. Solo estoy preocupado ¿por qué se opone? Alguien puede anularlo. –
@MikeChaliy Está destinado a implementar IAsyncResult, y es de solo lectura. Nadie puede anularlo una vez que construya su tarea. Es necesario para construir la tarea utilizando uno de los constructores que toma acción ''
ups @ReedCopsey, sí, tienes razón. Bueno, se ve aún mejor entonces. –