使用Object.factory而无需转换为特定类型

jar*_*ine 4 d

我正在尝试为Rails ActionDispatch路由器创建一个类似的路由器,它允许您定义类似的路由

map.get "/foo", :controller => "Foo", :action => "index"
Run Code Online (Sandbox Code Playgroud)

然后将路由GET /fooFooController#index.有了这个结构,你可以使用像

map.resources :foos
Run Code Online (Sandbox Code Playgroud)

这将调用像

map.get "/foo", :controller => "Foo", :action => "index"
map.get "/foo/:id", :controller => "Foo", :action => "show"
Run Code Online (Sandbox Code Playgroud)

等等.

在D中,我已经能够找出使这项工作所需的许多反身代码,但不是全部.在Ruby中我可以做到:

class Foo
  def bar
    "FOOO BAR!"
  end
end

f = Object.const_get("Foo")
f.new.__send__(:bar) #=> "FOOO BAR!"
Run Code Online (Sandbox Code Playgroud)

我试图翻译成

module foo;
import std.stdio;

class Foo {
  void bar() {
    writeln("FOO BAR!");
  }
}

void main() {
  auto foo = Object.factory("foo.Foo");
  __traits(getMember, foo, "bar");
}
Run Code Online (Sandbox Code Playgroud)

但这不起作用,因为编译器不知道什么类型foo,所以#bar在编译期间调用失败.我见过的所有地方都Object.factory将它们投射到特定类型,所以

module foo;
import std.stdio;

class Foo {
  void bar() {
    writeln("FOO BAR!");
  }
}

void main() {
  auto foo = cast(Foo) Object.factory("foo.Foo");
  __traits(getMember, foo, "bar");
}
Run Code Online (Sandbox Code Playgroud)

会工作得很好.但是,如果我知道我想把对象强加给什么好用的东西Object.factory?这对我没有任何意义!

更新2我已修复编译器问题,但现在它在运行时崩溃,说它无法找到该方法

module foo;
import std.stdio;

class MyDynamic {
  void call(C, T...)(C instance, string method, T args) {
    foreach(member; __traits(allMembers, C)) {
      writeln(member);
      if (member == method) {
        static if (__traits(compiles, __traits(getMember, instance, member)(args))) {
          __traits(getMember, instance, member)(args);
        }
        return;
      }
    }

    assert(0, "No method found");
  }
}

class Foo : MyDynamic {
  void bar() {
    writeln("FOO BAR!");
  }
}

void main() {
  auto foo = cast(MyDynamic) Object.factory("foo.Foo");
  assert(foo !is null);

  foo.call(foo, "bar");
}
Run Code Online (Sandbox Code Playgroud)

更新对于现在遇到此问题的任何人,您可以在此处查看我的最终解决方案:https://github.com/jaredonline/action-pack

Ada*_*ppe 5

我这样做的方法是建立自己的工厂功能和动态调度.使用__traits(allMembers),遍历所有支持的类并获取方法列表.编写一个包装器模板,它接受泛型参数并将它们转换为函数所需的参数.在关联数组中存储对包装函数的引用,或者在接口中使用调度方法来调用它.

当需要完成工作时,创建类(使用自己的包装器,或者也可以使用Object.factory将其转换为动态调度函数的通用接口),然后使用动态函数.所以类似于:

// IMPORTANT: Object.factory needs a full name - includes the module and class name!
auto foo = cast(MyDynamic) Object.factory("mymodule.Foo");
assert(foo !is null); // Object.factory can return null if it didn't find the class
// and cast can also return null if it wasn't actually of that interface type, so gotta check

foo.call("my_method", ["arg", "arg2", ...]);
Run Code Online (Sandbox Code Playgroud)

我用完整的示例更新了此链接,如果您没有module dynamicstuff;在顶部看到,请刷新:

http://arsdnet.net/dcode/test46.d

循环allMembers,根据运行时字符串调用.通过循环ModuleInfo,获取实现接口的所有类的列表也是可能的.请参阅示例文件的底部以获取执行此操作的功能.

我的web.d这样做是为了从网上自动调用功能.冗长,凌乱的代码,但它做了很多.这是包装函数:https: //github.com/adamdruppe/misc-stuff-including-D-programming-language-web-stuff/blob/master/web.d#L2538

请注意std.traits中ParameterTypeTuple!func的使用.

我在这里写了很多评论http://arsdnet.net/dcode/test46.d所以希望他们能回答你的问题.该示例简要说明:

  • 用__traits编译时间反射(MyDynamicImplementation)
  • 使用ModuleInfo和ClassInfo运行时反射(getAllDynamicClasses)
  • 用户定义的属性(isDynamicallyAvailable)
  • 使用动态数据调用方法(MyDynamicImplementation,如果您感兴趣,可以使用ReturnType,to,ParameterTypeTuple和Variant的注释代码)
  • 多重继承的替代方案,使用接口和mixin模板.

你不一定要使用所有这些东西,但我想我会触及所有这些,因为这些对于这些url路由任务都非常有用.