"Foo", :action =>-6ren">
gpt4 book ai didi

d - 使用 Object.factory 无需强制转换为特定类型

转载 作者:行者123 更新时间:2023-12-04 11:32:55 25 4
gpt4 key购买 nike

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

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

然后将路由 GET /fooFooController#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

最佳答案

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

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

// 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 来获取所有实现接口(interface)的类的列表也是可能的。有关执行此操作的函数,请参见示例文件的底部。

我的 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 的注释代码)
  • 多重继承的替代方案,同时使用接口(interface)和 mixin 模板。

  • 您不一定必须使用所有这些东西,但我想我会涉及所有这些,因为这些对于这些 url 路由任务都非常有用。

    关于d - 使用 Object.factory 无需强制转换为特定类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20451131/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com