思路:通过数据字典定义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运行时根据字典动态调用,如果你的开发框架里面或者中间件里面这样实现,简直帅呆了!