[英]Base class Task<> has no empty constructor
I have a C# code 我有一个C#代码
private class EvaluationTask : Task<Solution> {
private Problem problem_;
private Solution solution_;
public EvaluationTask(Problem problem, Solution solution)
{
problem_ = problem;
solution_ = solution;
}
}
Now, I am getting error System.Threading.Tasks.Task<>
does not contain constructor that takes 0 arguments. 现在,我收到错误
System.Threading.Tasks.Task<>
不包含带0参数的构造函数。 From previous answers posted, I found that one has to define empty constructor in the base class. 从之前发布的答案中,我发现必须在基类中定义空构造函数。 But since my base class is
Task<>
, how do I add an empty constructor to it? 但由于我的基类是
Task<>
,我该如何向它添加一个空构造函数?
Any help would be highly appreciated! 任何帮助将非常感谢!
Edit: I have to inherit task<> because I have to use the method EvaluationTask in a code: 编辑:我必须继承任务<>因为我必须在代码中使用EvaluationTask方法:
taskList_ = new List<Task<Solution>>();
taskList_.Add(new MultithreadedEvaluator.EvaluationTask (problem_, solution));
I don't know about task composition, so if it is necessary can anyone help with that? 我不知道任务组成,所以如果有必要,任何人都可以帮忙吗? Or if by any way I can avoid inheriting Task and still implement taskList_.Add()?
或者,如果以任何方式我可以避免继承任务并仍然实现taskList_.Add()?
When you inherit from a class, in your constructors you need to call any of the constructors of the base class. 从类继承时,在构造函数中需要调用基类的任何构造函数。 In your case, since you aren't calling any constructor, the compiler try to call a parameterless constructor of the base class, but
Task<>
haven't a parameterless constructor. 在您的情况下,由于您没有调用任何构造函数,编译器会尝试调用基类的无参数构造函数,但
Task<>
没有无参数构造函数。
As you can read here , inheriting from Task<>
probably isn't a good idea, but you can do something like this: 你可以在这里阅读,继承
Task<>
可能不是一个好主意,但你可以这样做:
class EvaluationTask : Task<Evaluation>
{
public EvaluationTask()
: base(DoWork) { }
private static Evaluation DoWork()
{
//...
}
}
When using Task<T>
, you must supply the Func<>
or Action<>
delegate (ie, function pointer to the desired work to perform) as a constructor argument . 使用
Task<T>
,必须提供Func<>
或Action<>
委托(即,要执行的所需工作的函数指针) 作为构造函数参数 。 It is indeed somewhat unfortunate that there isn't any constructor which lets you bypass this requirement and supply the delegate at a later time (yet obviously still prior to calling Start()
), since this severely hampers the ability to extend the Task
and Task<TResult>
classes via inheritance altogether. 确实有点不幸的是,没有任何构造函数允许您绕过此要求并在稍后提供代理(但显然仍然在调用
Start()
),因为这严重阻碍了扩展Task
和Task<TResult>
的能力Task<TResult>
类通过继承完全。
The reason it's a crippling omission is that no delegate you supply as a constructor argument can possibly directly incorporate a reference to the instance you are trying to construct, since that instance (again, obviously) doesn't exist yet, chicken/egg style. 这是一个令人遗憾的遗漏的原因是,你提供的构造函数参数的任何委托都不能直接包含对你想要构建的实例的引用,因为那个实例(显然,再次)还不存在,鸡/蛋样式。
Hence @Arturo's answer, which shows that you can, in fact, supply a static delegate, but since such a delegate has no obvious way of referencing one particular Task
instance, it essentially defeats the purpose of inheriting from Task
in the first place. 因此,@ Arturo的回答表明,事实上,你可以提供静态委托,但由于这样的委托没有明显的方法来引用一个特定的
Task
实例,所以它基本上违背了从Task
继承的目的。
--- reflection disclaimer ---
--- 反思免责声明 ---
I've been using this technique in my own projects for years on .NET Framework 4.7 (desktop) with no problems whatsoever, but please note that code which uses reflection to access non-public behavior is subject to breakage if the .NET internals change in a later version.我已经在我自己的项目中使用这种技术多年来在.NET Framework 4.7 (桌面)上没有任何问题,但请注意,如果.NET内部更改,使用反射来访问非公共行为的代码会受到破坏在更高版本中。 You have been warned.
你被警告了。
Here's a more flexible workaround for the problem, a general-purpose abstract base class for Task<TResult>
which allows you to provide the desired work code in the normal way for derived type hierarchies: as an instance method override. 这是针对该问题的更灵活的解决方法,
Task<TResult>
的通用抽象基类,它允许您以常规方式为派生类型层次结构提供所需的工作代码:作为实例方法覆盖。 This is a reflection solution; 这是一种反思解决方案; the way it works is to provide a dummy "placeholder" delegate to the base constructor call , but then immediately in the constructor body , swap it out for the "real," desired abstract instance work method, which at that point is no longer unknowable or rather unbindable .
它的工作方式是为基础构造函数调用提供一个虚拟的“占位符”委托,但是然后立即在构造函数体中 ,将其交换为“真实的”所需的抽象实例工作方法,此时该方法不再是不可知的或者说是不可能的 。
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
};
To use this, simply inherit from TaskBase<TResult>
, and override the abstract method function()
to implement your task work logic. 要使用它,只需从
TaskBase<TResult>
继承,并覆盖抽象方法function()
以实现任务工作逻辑。 There is no need for a version of this base class where the work function accepts a AsyncState
argument/parameter(s), since you can simply declare all the relevant context for the specific work instance as additional instance fields (and instance methods, and instance properties...) in your derived class. 不需要工作函数接受
AsyncState
参数/参数的此基类的版本,因为您可以简单地将特定工作实例的所有相关上下文声明为附加实例字段(以及实例方法和实例)属性...)在派生类中。 So the constructor variations I declared exactly match those provided by Task<TResult>
, but minus the 'function' and 'state' arguments. 所以我声明的构造函数变量与
Task<TResult>
提供的变量完全匹配,但减去了'function'和'state'参数。 And finally, don't forget to call Start()
when your packaged work instance is ready to go! 最后,当您的打包工作实例准备就绪时,不要忘记调用
Start()
!
The above is a actually a simplified version of the TaskBase<TResult>
code I've had much success with. 以上是
TaskBase<TResult>
代码的实际简化版本,我已经取得了很大的成功。 My enhanced version avoids creating the Func<TResult>
delegate which must be created for each TaskBase
instance in order to "wrap" the C# method function()
as an instance delegate. 我的增强版避免了创建必须为每个
TaskBase
实例创建的Func<TResult>
委托,以便将C#方法function()
“包装”为实例委托。 Instead of initially providing a 'dummy' delegate to the base constructor, I always provide (the same) static delegate, a singleton which acts as a "thunk" that universally reinterprets, or "upcasts" a Task<TResult>
's AsyncState
object as a pertinent TaskBase<TResult>
instance, and then calls function()
directly on that instance. 我总是提供(相同的)静态委托,而不是提供(相同的)静态委托,作为“thunk”的单例,它通用地重新解释或“向上转发”
Task<TResult>
的AsyncState
对象,而不是最初向基础构造函数提供“虚拟”委托。作为一个相关的TaskBase<TResult>
实例,然后直接在该实例上调用function()
。 Like so: 像这样:
static Func<Object,TResult> thunk = obj => ((TaskBase<TResult>)obj).function();
So fn_redirect
is the only "excess" delegate we need to create once at startup, and this singleton is always passed-in as the base constructor work delegate. 所以
fn_redirect
是我们在启动时需要创建的唯一“多余”委托,并且这个单例始终作为基础构造函数工作委托传入。 Now as with that constructor argument, the "async state" object is also only passed in as a constructor argument and normally cannot later be changed. 现在与该构造函数参数一样,“异步状态”对象也仅作为构造函数参数传递,通常以后不能更改。 We don't need a "dummy" in this approach, because you can--and should--pass in 'null' for
state
. 在这种方法中我们不需要“虚拟”,因为你可以 - 而且应该 - 为
state
传递'null'。 Similar to before we use reflection to set a field, but this time it's m_stateObject
field instead of m_action
, to replace the 'null' value we just installed for the instance this
pointer: 类似于我们使用反射之前设置一个领域,但这次是
m_stateObject
场,而不是m_action
,以取代我们刚刚安装实例的“空”值this
指针:
public TaskBase(CancellationToken ct, TaskCreationOptions opts)
: base(thunk, default(Object), ct, opts)
{
m_stateObject.SetValue(this, this);
}
Voila, allocating one extra delegate for each TaskBase
instance is avoided. 瞧,避免为每个
TaskBase
实例分配一个额外的委托。 Finally, recall that there are no adverse loss of capability when co-opting the state object for the purpose of this enhancement because as I mentioned earlier, the whole AsyncObject
argument-passing mechanism is unnecessary when you entirely control the derived class you are writing. 最后,回想一下,为了这个增强而选择状态对象时没有不利的能力损失,因为正如我前面提到的,当你完全控制你正在编写的派生类时,整个
AsyncObject
参数传递机制是不必要的。
Here is an inheritable class that inherits from Task<T>
, and allows delayed assignment of the task's function. 这是一个继承自
Task<T>
的可继承类,允许延迟分配任务的功能。 The constructor takes no arguments. 构造函数不带参数。 The function is assigned by the property
Function
. 该功能由属性
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;}
}
}
Usage Example: 用法示例:
public class EvaluationTask : FlexibleTask<int>
{
}
var task = new EvaluationTask();
task.Function = () => 13;
task.Start();
var result = await task;
Console.WriteLine($"Result: {result}");
Output: 输出:
Result: 13
结果:13
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.