问题
I want to add some functionality to ITask/TTask. I wrapped the new methods in a new Interface (IMyTask) which inherits from ITask:
type
IMyTask = interface(ITask)
procedure MyNewMethod;
end;
TMyTask = class(TTask, ITask, IMyTask)
private
FSomeList: TList<integer>;
public
procedure MyNewMethod;
constructor Create(const AProc: TProc; AThreadPool: TThreadPool = nil); overload;
constructor Create(Sender: TObject; Event: TNotifyEvent); overload;
constructor Create(const Proc: TProc); overload;
constructor Create(Sender: TObject; Event: TNotifyEvent; const APool: TThreadPool); overload;
end;
My class contains members that should be initialized in its constructor (for example FSomeList). So calling my constructor is mandatory. In the same time I didn't want to change the implementation of Create(). So I re declared Create() as constructor with four overrides. But creating an instance of TMyTask fails to compile with E2251:
procedure TestCreateMyTask;
var
i: IMyTask;
begin
i := TMyTask.Create( // --> E2251 Ambiguous overloaded call to 'Create'
procedure
begin
end
);
end;
I tried with "Reintroduce" keyword but it seems not to work may be because all Create() methods are marked with "Overload".
How to overcome this problem?
UPDATE:
Further tests resulted in two QCs:
- QC129032: Using TTask.WaitForAll() causes a deadlock
- QC129032: ITask.Cancel does not process complete events
回答1:
Why do you feel you should create a TTask descendant? You should not create a TTask descendant except in very rare circumstances. The better solution is to use a regular task within another object.
The Create methods on TTask aren't actually constructors, rather they're static class functions. The reason for this is to ensure that you only ever work with an ITask and not the TTask directly. You also cannot construct a TTask with the default parameter-less constructor (it raises an exception). The source even has a comment near that constructor
constructor Create; overload; // do not call this constructor!!
The difference between the "Create" functions and the "Run" functions is whether or not the task is scheduled. Run will return a task already scheduled into the thread pool. Create will defer that to when the caller decides to schedule it.
class function Create(Sender: TObject; Event: TNotifyEvent): ITask; overload; static; inline;
class function Create(const Proc: TProc): ITask; overload; static; inline;
class function Create(Sender: TObject; Event: TNotifyEvent; const APool: TThreadPool): ITask; overload; static; inline;
class function Create(const Proc: TProc; APool: TThreadPool): ITask; overload; static; inline;
class function Run(Sender: TObject; Event: TNotifyEvent): ITask; overload; static; inline;
class function Run(Sender: TObject; Event: TNotifyEvent; APool: TThreadPool): ITask; overload; static; inline;
class function Run(const Func: TProc): ITask; overload; static; inline;
class function Run(const Func: TProc; APool: TThreadPool): ITask; overload; static; inline;
As I said, it is better to simply use the TTask Create or Run methods directly and not create a descendant. If you want to encapsulate the task's operations, feel free to create your own class type and internally create and schedule the task(s).
来源:https://stackoverflow.com/questions/27081623/sub-classing-ttask-in-xe7-e2251-ambiguous-overloaded-call-to-create