我有一个日志记录类,与许多模块相关联。该类的主方法是一个类方法:
type
TSeverity = (seInfo, seWarning, seError);
TLogger = class
class procedure Log(AMessage: String; ASeverity: TSeverity);
end;
在别的地方,我有一个名为
DoSomething()
的函数,它会做一些事情,我想记录下来。但是,我不想将所有记录器模块链接到声明DoSomething()
的模块中以使用记录器。相反,我想将任意的日志方法作为DoSomething()
的参数传递,并从其体内调用它。问题在于
TLogger.Log
需要TSeverity
类型的参数,而该类型定义在记录器类中。因此,我无法定义该类型:type
TLogProcedure = procedure(AMessage: String; ASverity: TSeverity) of Object;
因为我需要包含一个声明了TSeverity
的单元。
我试图想出一些基于通用过程的解决方案,但是我卡住了。
uses
System.SysUtils;
type
TTest = class
public
class function DoSomething<T1, T2>(const ALogProcedure: TProc<T1,T2>): Boolean; overload;
end;
implementation
class function TTest.DoSomething<T1, T2>(const ALogProcedure: TProc<T1, T2>): Boolean;
var
LMessage: String;
LSeverity: Integer;
begin
//Pseudocode here I would like to invoke logging procedure here.
ALogProcedure(T1(LMessage), T2(LSeverity));
end;
在代码的其他位置,我希望使用DoSomething
。
begin
TTest.DoSomething<String, TSeverity>(Log);
end;
感谢您的帮助。
更新
也许我表达不够清楚。
unit uDoer;
interface
type
TLogProcedure = procedure(AMessage: String; AErrorLevel: Integer) of Object;
// TDoer knows nothing about logging mechanisms that are used but it allows to pass ALogProcedure as a parameter.
// I thoight that I can somehow generalize this procedure using generics.
type
TDoer = class
public
class function DoSomething(const ALogProcedure: TLogProcedure): Boolean;
end;
implementation
class function TDoer.DoSomething(const ALogProcedure: TLogProcedure): Boolean;
begin
ALogProcedure('test', 1);
Result := True;
end;
end.
使用其中一种日志记录机制来分离单元。
unit uLogger;
interface
type
TSeverity = (seInfo, seWarning, seError);
// I know that I could solve my problem by introducing an overloaded method but I don't want to
// do it like this. I thought I can use generics somehow.
TLogger = class
class procedure Log(AMessage: String; ASeverity: TSeverity); {overload;}
{class procedure Log(AMessage: String; ASeverity: Integer); overload;}
end;
implementation
class procedure TLogger.Log(AMessage: String; ASeverity: TSeverity);
begin
//...logging here
end;
{class procedure TLogger.Log(AMessage: String; ASeverity: Integer);
begin
Log(AMessage, TSeverity(ASeverity));
end;}
end.
两个单元的使用示例。
implementation
uses
uDoer, uLogger;
procedure TForm10.FormCreate(Sender: TObject);
begin
TDoer.DoSomething(TLogger.Log); //Incompatible types: Integer and TSeverity
end;
TSeverity
的定义从日志模块中提取出来,放到一个单独的模块中,并在两个地方使用这个新模块。现在它不再是日志模块的一部分,因此你就没有那个依赖了。” - Ken White