Reflection D有反射吗?

Reflection D有反射吗?,reflection,d,Reflection,D,D是否有反射或任何接近它的东西,以便能够在运行时访问对象 如果没有: 在运行时如何访问或编辑对象 例如: bool myFunc(string status){ switch(status){ case "create": Object my_obj = new createObject(); write("Object has been created or whatever"); break;

D是否有反射或任何接近它的东西,以便能够在运行时访问对象

如果没有:

在运行时如何访问或编辑对象

例如:

bool myFunc(string status){
    switch(status){
        case "create":
            Object my_obj = new createObject();
            write("Object has been created or whatever");
        break;

        case "mutate":
            //Don't want to have to make a global declaration
            my_obj.attribute = "A meme";
            write("Object has been mutated or whatever");
        break;

        case "delete":
            //Don't want to have to make a global declaration
            delete();
            write("Object has been deleted or whatever");
        break;

        default:
        //blah
        break;
    }


    return true;
}



void main(){
while(true)
{String status = readln();myFunc(status);}



}
这就是我目前所能想到的,请让我知道我对D在这个话题上的误解

我已经浏览了dlang.org上的文档,没有找到与反射有关的东西,或者至少没有找到Java的方式


ps,上面的代码是我在现场编写的伪代码,我确信不管出于什么原因它实际上不会编译,我只是希望通过一种特定的方式访问对象,这样对我来说很方便。

是的,D有反射,但不,它不像Java

D的反射以编译时构建块的形式出现,而不是运行时方法。当然,您可以自己创建运行时方法,但这并不是所有东西都可以开箱即用

实际上,我今天刚刚写了一个东西,反射在一个方法上循环,以显示其属性,并允许您编辑它:它还没有完成,但我将链接,以便您可以看到它的一些操作:

无论如何,我这样做的方式是使用反射信息从简单循环中创建方法。该语言提供了两种功能,即特征,表达式用于实现这一点:

标准库使用std.traits模块进行包装和扩展

(或者,如果你更喜欢基本相同文档的官方网站,只是我更难阅读/浏览:)

您可以将其与其他代码生成技术(如模板混合)和传统的东西(如接口和构造函数)结合起来创建运行时内容

但对于一个简单的情况,请尝试以下方法:

import std.stdio;
import std.conv;
import std.traits;

class MyClass {
    void myMethod() {}
    int anotherMethod(int a) { return a; }

    // this is the runtime bridge function. The trick here is to do
    // a switch, just like your example, but the innards are auto-generated
    // from the compile time reflection.
    string call(string methodName, string[] args) {
        // it starts as a plain switch...
        method_switch: switch(methodName) {
            // but inside, we use a static foreach - a compile-time loop -
            // over the __traits(allMembers) magic, which gives a list of all member names
            static foreach(inspecting; __traits(allMembers, typeof(this))) {
                case inspecting: { // you can create switch cases inside these static loops
                    // for this example, I only want to use callable methods, so this
                    // static if - a compile time if statement - will filter out anything else.
                    //
                    // It is possible to do more, like plain data members, child classes, and more,
                    // but that will add a lot more code. Same basic ideas with each of them though.
                    static if(isCallable!(__traits(getMember, this, inspecting))) {
                        // after we confirm it is callable, we can get a delegate of it
                        // (same as normally doing `&member.method`) to call later.
                        auto callable = &__traits(getMember, this, inspecting);

                        // next is building the argument list. Parameters comes from the std.traits
                        // module in the standard library and gives an object representing the function's
                        // parameters. We can loop over these and set them!
                        Parameters!callable arguments;
                        foreach(i, ref arg; arguments) { // ref loop cuz we setting the arg members..
                            // so for the runtime bridge here, I took everything as strings and
                            // want to convert them to the actual method arguments. In many cases,
                            // that automatic conversion will not be possible. The next bit of magic,
                            // __traits(compiles), will take some code and return true if it successfully
                            // compiles. Using the static if block, I can turn what would be compile time
                            // errors into a runtime exception instead.
                            static if(__traits(compiles, to!(typeof(arg))(args[i])))
                                // note that to is from the stdlib again: std.conv. It converts
                                // a thing from one type to another. Here, I ask it to convert our
                                // string (args is the runtime array of strings the user passed) to
                                // whatever the type is that the method expects.
                                //
                                // Note that this might throw an exception if the string is wrong.
                                // For example, passing "lol" to a method expecting an int will throw
                                // an exception saying cannot convert string "lol" to int.
                                arg = to!(typeof(arg))(args[i]);
                            else
                                // or if the conversion didn't compile at all, it will always throw.
                                throw new Exception("method " ~ methodName ~ " not callable with this reflection code because of incompatible argument type");
                        }

                        // now that we have the arguments, time to tackle the return value.
                        // the main special case here is a void return - that is not a value
                        // and thus cannot be converted. So we do it separately.

                        // Otherwise, though, inside we just call our callable from above with
                        // the arguments from above and return the value converted to string!

                        static if(is(ReturnType!callable == void)) {
                            // it returned void, so call it and return null
                            // because the language won't let us return void
                            // directly as a string nor convert it easily.
                            callable(arguments);
                            return null;
                        } else {
                            // it returned something else, just call the function
                            // and convert it to a string
                            return to!string(callable(arguments));
                        }
                    }
                } break method_switch;
            }
            default:
                throw new Exception("no such method " ~ methodName);
        }

        assert(0); // not reached
    }
}

// and let's call them with some strings. You could also get these strings from
// the user (just btw remember to .strip them if they come from readln, otherwise
// the trailing newline character will cause a method not found exception.)
void main() {
    auto obj = new MyClass();
    writeln(obj.call("myMethod", []));
    writeln(obj.call("anotherMethod", ["5"]));
}
从网站上复制/粘贴代码并在常规编辑器中阅读注释可能会有所帮助,因为堆栈溢出通常会使您滚动,这很困难。我在评论中展示了基本观点

一旦你写了一次反射桥函数,并使它以某种方式工作,你会对它感到满意。。。您可以添加任意数量的方法,它将起作用

事实上,您甚至可以将
调用
方法作为接口的一部分,以及
mixin模板的主体部分的定义
(请参阅),并将其弹出到任何类中

class MyNewClass : Reflectable {
    mixin CallImplementation;
}

// it will now work there!
该接口允许您从基类引用它(在大多数情况下与Java相同),而mixin模板允许您将反射提供程序复制到每个子类中,因此它提供了所有方法,甚至是子类上的方法。Java会自动为您做到这一点,但在D中,您确实需要将该mixin行添加到每个mixin行中。不是太麻烦,而是要考虑的事情。(实际上,D也可以自动完成。但是它需要对核心运行时库进行黑客攻击,因此这是一个相当高级的主题,仅在特殊情况下有用(因为您必须在整个项目范围内使用被黑客攻击的库)。因此,可能对您没有用处,只是暗示它就在那里。)

使用接口btw,您还可以向类添加静态构造函数,以便将它们注册到一些运行时关联数组中,或将类名称切换到工厂函数,并从字符串创建它们。没有特别的代码来实现这一点,这是您以前可能见过的同一种模式,但是如果您需要从字符串中创建新的类对象,而不仅仅是编辑现有对象,那么我将从这里开始


不过,我将把这些细节留给您来处理,让我知道这里的任何内容是否有意义。

D编程语言支持编译时反射,但不支持运行时反射(例如Java)。有关编译时反射的更多详细信息,请参见Adam的答案


10多年前,托马斯·库恩(Thomas Kühne)写了一个名为FlectioneD()的优秀软件包,它仍然是这个主题的一个很好的参考…

顺便说一句,我在我的书的反射章节中也谈到了这一点和更多类似的内容:那曾经是免费的示例章节,但看起来他们改变了这一点。。。尽管如此,如果这个答案不能满足您的需求,您可能可以从中获得更多。嘿,这可能是一个愚蠢的问题,但是您可以调用构造函数并使用您的反射版本设置它吗?比如:auto obj=new MyClass();writeln(对象调用(“MyClass”、“attribute1”、“attribute2”、“attribute3”);可以,但它不会自动覆盖这样的构造函数。您必须自己将它们添加到交换机中。