2013-12-08 36 views
4

我试图创建一个类似路由器的Rails ActionDispatch路由器,它允许您定义使用Object.factory无需强制转换为特定类型

map.get "/foo", :controller => "Foo", :action => "index" 

这也就那么路线GET /foo类似的路线到FooController#index。采用这种结构的地方,你可以像使用

map.resources :foos 

方法,它将调用的方法,如

map.get "/foo", :controller => "Foo", :action => "index" 
map.get "/foo/:id", :controller => "Foo", :action => "show" 

等。

在D中,我已经能够弄清楚需要完成这项工作的许多反身代码,但不是全部。在Ruby中我可以这样做:

class Foo 
    def bar 
    "FOOO BAR!" 
    end 
end 

f = Object.const_get("Foo") 
f.new.__send__(:bar) #=> "FOOO BAR!" 

我已经试着翻译成

module foo; 
import std.stdio; 

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

void main() { 
    auto foo = Object.factory("foo.Foo"); 
    __traits(getMember, foo, "bar"); 
} 

但是,这并不工作,因为编译器不知道什么类型的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"); 
} 

会工作得很好。但是,如果我知道我想要将物体投射到什么样的物体使用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"); 
} 

更新对于没有人来对这个问题,现在,你可以看到我的最终解决方案在这里:https://github.com/jaredonline/action-pack

+0

虽然,目前我D是segfaulting,我不知道为什么。 – jaredonline

+0

“现在它在运行时崩溃,说它找不到方法”,这是因为你的上下文中的'C'被推断为'MyDynamic',而不是'Foo'。没有某种'ClassInfo'帮助进行运行时反射是不可能的。 –

+0

什么样的'ClassInfo'帮助? – jaredonline

回答

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", ...]); 

我更新该链接,以一个完整的例子,如果刷新你看不到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路由任务都非常有用。

+0

我更新了自己的样本和解释中提出的问题,但我仍然错过了一些我认为的关键理解。 – jaredonline

+0

好的,所以我修复了编译器问题,但现在我遇到了同样的问题,我需要将对象转换为正确的类才能工作。 – jaredonline

+0

有没有办法获得从MyDynamic继承的所有类的列表? – jaredonline

相关问题