DELPHI RTTI实现非可视的功能插件

思路:通过数据字典定义BPL包名,然后定义BPL包里面的类名,然后定义类里面的方法名,最后定义方法的参数值。

可实现动态加载BPL,调用哪个BPL的哪个类的哪个方法并给该方法赋给指定的参数值,如果是函数还可以取得函数的返回值。

应用场合之一:中间件实现非可视功能插件。

下面来DEMO码子。

首先动态加载BPL包:

bplName := TPlug(TdxBarButton(Sender).Tag).bplName;

if FileExists(bplName) then

begin

unitClass := string(TPlug(TdxBarButton(Sender).Tag).UnitCalss);

plugName := TPlug(TdxBarButton(Sender).Tag).description;

powerValue := TPlug(TdxBarButton(Sender).Tag).powerValue;

if not bplList.ContainsKey(bplName) then

begin

h := LoadPackage(bplName);

if h = 0 then

ShowTrayHint(bplName + '包加载失败')

else

bplList.Add(bplName, h);

end;

然后获取BPL的对象

var

LContext: TRttiContext;

LPackage: TRttiPackage;

LClass: TRttiInstanceType;

aForm: TCustomForm;

begin

LContext := TRttiContext.Create;

try

for LPackage in LContext.GetPackages() do

begin

if SameText(ExtractFileName(LPackage.Name), bplFile) then

begin

LClass := LPackage.FindType(unitClass) as TRttiInstanceType;

aForm := LClass.MetaclassType.Create as TCustomForm;

end

finally

LContext.Free;

end;

最后传递参数调用类的方法

TMyClass = class(TComponent)

public

procedure msg(const str: string);

function Add(const a,b: Integer): Integer;

end;

var

Form1: TForm1;

implementation

{$R *.dfm}

{ TMyClass }

procedure TMyClass.msg(const str: string);

begin

MessageDlg(str, mtInformation, [mbYes], 0);

end;

function TMyClass.Add(const a, b: Integer): Integer;

begin

Result := a + b;

end;

procedure TForm1.Button1Click(Sender: TObject);

var

obj: TMyClass;

t: TRttiType;

m1,m2: TRttiMethod;

r: TValue; //TRttiMethod.Invoke 的返回类型

begin

t := TRttiContext.Create.GetType(TMyClass);

{获取 TMyClass 类的两个方法}

m1 := t.GetMethod('msg'); {procedure}

m2 := t.GetMethod('Add'); {function}

obj := TMyClass.Create(Self); {调用需要依赖一个已存在的对象}

{调用 msg 过程}

m1.Invoke(obj, ['Delphi 2010']); {将弹出信息框}

{调用 Add 函数}

r := m2.Invoke(obj, [1, 2]); {其返回值是个 TValue 类型的结构}

ShowMessage(IntToStr(r.AsInteger)); {3}

obj.Free;

end;

代码只是为了演示这么个意思,你懂的。

以上的一切都是通过字典定义,RTTI运行时根据字典动态调用,如果你的开发框架里面或者中间件里面这样实现,简直帅呆了!