工作時,建立類(使用自己包裝器,或可用
Object.factory
并用
動态排程
函數把它轉換為某個
通用接口
),然後使用
動态函數
.就像:
// 注意: 工廠要`子產品+類`全名
auto foo = cast(MyDynamic) Object.factory("mymodule.Foo");
assert(foo !is null); // 找不到,為`無效`.
foo.call("my_method", ["arg", "arg2", ...]);
module dynamicstuff;
import std.variant;
import std.conv;
import std.traits;
// 接口,這樣它就不會妨礙`多重`繼承
interface MyDynamic {
Variant callMethod(string method, string[] arguments);
}
enum DynamicallyAvailable;
//使用者定義注解來檢視是否可用`該方法`
// 檢視`上面`屬性是否在`成員`上
bool isDynamicallyAvailable(alias member)() {
// 取屬性
foreach(annotation; __traits(getAttributes, member))
static if(is(annotation == DynamicallyAvailable))
return true;
return false;
}
alias Helper(alias T) = T;
// 反射時更短.
mixin template MyDynamicImplementation() {
override Variant callMethod(string methodNameWanted, string[] arguments) {
foreach(memberName; __traits(allMembers, typeof(this))) {
if(memberName != methodNameWanted)
continue;
static if(__traits(compiles, __traits(getMember, this, memberName))) {
//過濾私成員
alias member = Helper!(__traits(getMember, this, memberName));//可用`member`
// 隻對`可用`的函數感興趣
static if(is(typeof(member) == function) && isDynamicallyAvailable!member) {
// 調用它.
ParameterTypeTuple!member functionArguments;
// 不變,不編譯
foreach(index, ref arg; functionArguments) {
if(index >= arguments.length)
throw new Exception("參數不夠" ~ methodNameWanted);
// 這裡為串.
arg = to!(typeof(arg))(arguments[index]);
// arg = arguments[index].get!(typeof(arg));
}
Variant returnValue;
// 取傳回值,檢查空.
static if(is(ReturnType!member == void))
member(functionArguments);
else
returnValue = member(functionArguments);
return returnValue;
}
}
}
throw new Exception("無此" ~ methodNameWanted);
}
}
// 可調用
class MyClass : MyDynamic {
mixin MyDynamicImplementation!();
@DynamicallyAvailable
void method(int param) {
import std.stdio;
writeln("哈哈", param);
}
}
class MySubClass : MyClass {
// 子類,用插件來注冊
mixin MyDynamicImplementation!();
@DynamicallyAvailable
void childMethod(int param) {
import std.stdio;
writeln("子類哈哈", param);
}
}
void main(string[] args) {
MyDynamic mc;
if(args.length > 1)
mc = cast(MyDynamic) Object.factory(args[1]); //全名.
if(mc is null)
throw new Exception("非動态" ~ to!string(getAllDynamicClasses()));
// 方法清單,插件模闆
mc.callMethod(args[2], args[3 .. $]);
}
/*
運作時取類清單
*/
string[] getAllDynamicClasses() {
string[] list;
// 取`object.d`中的`ModuleInfo`
foreach(mod; ModuleInfo) {
classList: foreach(classInfo; mod.localClasses) {
// 頂級類
if(doesClassMatch(classInfo))
list ~= classInfo.name;
}
}
return list;
}
// 運作時資訊
bool doesClassMatch(ClassInfo classInfo) {
foreach(iface; classInfo.interfaces) {
// 全名
if(iface.classinfo.name == "dynamicstuff.MyDynamic") {
return true;
}
}
// 可能在基類.
if(classInfo.base !is null)
return doesClassMatch(classInfo.base);
return false;
}