我有一个C#代码
private class EvaluationTask : Task<Solution> {
private Problem problem_;
private Solution solution_;
public EvaluationTask(Problem problem, Solution solution)
{
problem_ = problem;
solution_ = solution;
}
}
现在,我收到错误System.Threading.Tasks.Task<>
不包含带0参数的构造函数。从之前发布的答案中,我发现必须在基类中定义空构造函数。但由于我的基类是Task<>
,我该如何向它添加一个空构造函数?
任何帮助都将受到高度赞赏!
编辑:我必须继承任务&lt;&gt;因为我必须在代码中使用EvaluationTask方法:
taskList_ = new List<Task<Solution>>();
taskList_.Add(new MultithreadedEvaluator.EvaluationTask (problem_, solution));
我不了解任务组成,所以如果有必要,任何人都可以帮忙吗?或者,如果以任何方式我可以避免继承任务并仍然实现taskList_.Add()?
答案 0 :(得分:2)
从类继承时,在构造函数中需要调用基类的任何构造函数。在您的情况下,由于您没有调用任何构造函数,编译器会尝试调用基类的无参数构造函数,但Task<>
没有无参数构造函数。
正如您可以阅读here,继承Task<>
可能不是一个好主意,但您可以这样做:
class EvaluationTask : Task<Evaluation>
{
public EvaluationTask()
: base(DoWork) { }
private static Evaluation DoWork()
{
//...
}
}
答案 1 :(得分:1)
使用Task<T>
时,必须提供Func<>
或Action<>
委托(即,指向要执行的所需工作的函数指针)作为构造函数参数 。确实有点遗憾,没有任何构造函数可以让您绕过此要求并在以后的时间(尽管显然仍在调用Start()
之前)提供委托,因为这会严重阻碍能够通过继承完全扩展Task
和Task<TResult>
类。
这是一个令人毛骨悚然的遗漏的原因是,您提供的没有任何委托作为构造函数参数可以直接将对您尝试构造的实例的引用合并,因为该实例(显然,再次存在)尚不存在,cken /鸡蛋风格。
因此,@ Arturo的回答表明,您实际上可以提供 静态 委托,但是由于这样的委托没有明显的方式引用一个特定的{ {1}}实例,从根本上说,它就没有实现从Task
继承的目的。
--- 反射免责声明 ---
我已经在自己的项目中使用多年了。 NET Framework 4.7 (台式机)没有任何问题,但是请注意,如果.NET内部版本在以后的版本中发生更改,则使用反射来访问非公共行为的代码可能会损坏。您已被警告。
这是解决该问题的更灵活的解决方法,它是Task
的通用抽象基类,它允许您以正常方式为派生类型层次结构提供所需的工作代码:作为实例方法的替代。这是一种反射解决方案;它的工作方式是为 base构造函数调用提供一个虚拟的“占位符”委托,然后立即在 constructor主体中将其替换为“ real”,所需的抽象实例工作方法,在这一点上,它不再是不可知的,甚至是 unbindable 。
Task<TResult>
要使用此功能,只需从abstract class TaskBase<TResult> : Task<TResult>
{
readonly static FieldInfo m_action =
typeof(Task).GetField("m_action", BindingFlags.Instance | BindingFlags.NonPublic);
readonly static Func<TResult> _dummy = () => default;
public TaskBase(CancellationToken ct, TaskCreationOptions opts)
: base(_dummy, ct, opts) =>
m_action.SetValue(this, (Func<TResult>)function);
public TaskBase(CancellationToken ct)
: this(ct, TaskCreationOptions.None)
{ }
public TaskBase(TaskCreationOptions opts)
: this(default, opts)
{ }
public TaskBase()
: this(default, TaskCreationOptions.None)
{ }
protected abstract TResult function(); // <-- override with your work code
};
继承,并覆盖抽象方法TaskBase<TResult>
即可实现您的任务工作逻辑。不需要此基类的版本,工作函数可以接受function()
参数/参数,因为您可以简单地将特定工作实例的所有相关上下文声明为其他实例字段(和实例)。方法和实例属性...)。因此,我声明的构造函数变体与AsyncState
提供的变体完全匹配,但减去了“函数”和“状态”自变量。最后,当打包的工作实例准备就绪时,别忘了调用Task<TResult>
!
以上内容实际上是我成功使用过的Start()
代码的简化版本。我的增强版本避免创建TaskBase<TResult>
委托,而必须为每个Func<TResult>
实例创建一个委托才能将C#方法TaskBase
作为实例委托“包装”。我始终没有提供(相同的)静态委托,而是一个静态的单一委托,它充当普遍地重新解释或“伪造” function()
的{ {1}}作为相关Task<TResult>
实例的对象,然后直接在该实例上调用AsyncState
。像这样:
TaskBase<TResult>
因此function()
是我们在启动时需要创建的唯一“多余”委托,并且该单例始终作为基本构造函数工作委托传入。现在,与该构造函数自变量一样,“异步状态”对象也仅作为构造函数自变量传递,通常以后不能更改。我们不需要这种方法,因为您可以并且应该为static Func<Object,TResult> thunk = obj => ((TaskBase<TResult>)obj).function();
传递'null'。与之前我们使用反射来设置字段类似,但是这次是fn_redirect
字段而不是state
,用来替换我们刚刚为实例m_stateObject
指针安装的'null'值:< / p>
m_action
Voila,避免为每个this
实例分配一个额外的委托。最后,回想一下,为实现此增强而选择状态对象没有任何不利影响,因为正如我之前提到的,当您完全控制派生类时,不需要整个public TaskBase(CancellationToken ct, TaskCreationOptions opts)
: base(thunk, default(Object), ct, opts)
{
m_stateObject.SetValue(this, this);
}
参数传递机制写作。
答案 2 :(得分:0)
这是一个继承自Task<T>
的可继承类,它允许延迟分配任务的功能。构造函数不带任何参数。该功能由属性Function
分配。
public class FlexibleTask<T> : Task<T>
{
private readonly Helper _helper;
public Func<T> Function { set { _helper.SetFunction(value); } }
public FlexibleTask() : base(GetFunction())
{
this._helper = TempHelper;
TempHelper = null;
}
private static Func<T> GetFunction()
{
Func<T> function = Default;
var helper = new Helper();
helper.SetFunction = f => function = f;
TempHelper = helper;
return () => function();
}
private static readonly Func<T> Default = () =>
throw new InvalidOperationException("Function is not set.");
[ThreadStatic] private static Helper TempHelper;
private class Helper
{
public Action<Func<T>> SetFunction {get; set;}
}
}
用法示例:
public class EvaluationTask : FlexibleTask<int>
{
}
var task = new EvaluationTask();
task.Function = () => 13;
task.Start();
var result = await task;
Console.WriteLine($"Result: {result}");
输出:
结果:13