天天看點

d工廠取資訊

工作時,建立類(使用自己包裝器,或可用​

​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;
}