2014-04-15 2 views
4

좋아, 내가하려고하는 것은 요정이 복잡하지만 설명하려고 노력할 것입니다.문자열에서 클래스 가져 오기 - 문자열 이름으로 함수 호출

someClassderivedMembers을 모두 (컴파일 타임에) 원한다고 가정 해 봅시다. 그런 다음 우리는 간단하게 할 거라고 :

이제
const string[] methods = [__traits(derivedMembers,someClass)]; 

, 우리가 어떻게 "someClass"에서 someClass을 얻을 수 있을까? (예, 해당 문자열 표현).


나를 조금 더 내가 할 노력하고있어 설명하자

을 내가 (A PARAMS 배열과 함께) 인수로 function 이름을 취하는 "중간"기능을 만들려하고 특정 (미리 정의 된) 클래스 집합에서 사용 가능한 정적 메서드 목록에서 적절한 함수를 호출합니다. execute("someFunc",["one","two","three"]);처럼.

class Math { 
    static string noArgs(string[] s) { writeln(s); return ""; } 
    static string withOneArg(string[] s) { writeln(s); return ""; } 
    static string withTwoArgs(string[] s) { writeln(s); return ""; } 
} 

string cases() 
{ 
    string ret = ""; 

    const string[] methods = [__traits(derivedMembers,Math)]; 

    foreach (string s; methods) 
    { 
     ret ~= "case \"" ~ s ~ "\": return Math."~s~"(params);"; 
    } 

    return ret; 
} 

string execute(string what, string[] params) 
{ 
    switch (what) 
    { 
     mixin(cases()); 
     default: break; 
    } 
    return ""; 
} 

위의 코드의 문제점은 단지 Math의 방법을 찾는 것입니다 :

다음은 전체 (검사) 코드입니다. 어떻게 우아하게 D- 친숙한 방식으로 변경하여 [Math,String,SomethingElse]과 같은 클래스 배열을 통해 갈 수 있습니다 - 가변적 일 필요는 없습니다 (어쨌든 컴파일 타임에 필요합니다)?


UPDATE :의 라인을 따라

시도 뭔가 :

const string[] methods = [__traits(derivedMembers,mixin("Math")]; 

있지만 Cannot interpret Math at compile time 있음을 뿌려줍니다.


업데이트 2 : 또한

Object.factory("Math")를 사용하여 시도하지만 여전히 작동하지 않습니다. (아마도 난 그냥 Math 클래스의 인스턴스를 만드는거야?)

+0

'Object.factory ("com.example.kameleon.Math");'와 같은 정규화 된 이름으로 시도 했습니까? – DejanLekic

+0

@DejanLekic'mixin (className)'을 사용하여 그 부분을 해결 한 것 같습니다 (마침내 효과가있었습니다). 그러나 그것은 아직도 ok가 아니다. 여기를보십시오 : http://stackoverflow.com/questions/23078009/use-a-loop-at-compile-time –

+0

Object.factory는 나중에 인스턴스를 다시 캐스팅하거나 인터페이스를 통해 사용할 수 있도록 인스턴스를 만듭니다. 그것은 비록 컴파일 시간 반영을 위해 유용하지 않습니다. –

답변

5

은 내가 당신에게 멋진 트릭을 보여주기 위해이를 다시 보자 : 모든 사용에는 mixin 표현이 없는지

import std.stdio; 

class Math { 
    static string noArgs(string[] s) { writeln(s); return ""; } 
    static string withOneArg(string[] s) { writeln(s); return ""; } 
    static string withTwoArgs(string[] s) { writeln(s); return ""; } 
} 

class String { 
    static string oneArg(string[] s) { return null; } 
} 

string execute(string what, string[] params) { 
    import std.string; 
    auto parts = what.split("."); 
    auto className = parts[0]; 
    auto methodName = parts[1]; 

    import std.typetuple; 
    switch(className) { 
     default: assert(0, "unknown class"); 
     foreach(possibleClass; TypeTuple!(Math, String)) { 
      case possibleClass.stringof: 
       switch(methodName) { 
        default: assert(0, "unknown method"); 
        foreach(memberName; __traits(derivedMembers, possibleClass)) { 
         case memberName: 
          return __traits(getMember, possibleClass, memberName)(params); 
         break; 
        } 
       } 
      break; 
     } 
    } 
    assert(0); 
} 

void main() { 
    execute("Math.withOneArg", ["cool"]); 
    execute("String.oneArg", ["cool"]); 
} 

알 수 있습니다. 문자열에서 클래스의 인스턴스를 가져 오는 대신, 방금 사용하려는 모든 클래스 중 TypeTuple을 만들었습니다. 이것은 mixin보다 바람직합니다. 왜냐하면 다른 범위에서 사용될 때 이름 클래스를 찾기가 쉽지 않기 때문입니다. possibleClasses이 다른 모듈의 execute에 대한 컴파일 타임 매개 변수 인 경우 클래스 목록은 여전히 ​​작동하지만 라이브러리 모듈은 사용자 모듈을 가져 오지 않으므로 문자열 목록에 정의되지 않은 식별자 오류가 표시됩니다.

또 다른 mixin 사례를 생성하는 것이 제거되었습니다. 컴파일 시간이 foreach 인 경우 (예 : 일종의 내장 튜플에 foreach) D가 허용됩니다.TypeTuple, 템플릿 인수 목록, 결과는 __traits ...) 실제로 그 안에 case 문을 넣을 수 있습니다! 당신이 case that_loop_var: 붐, 검색하는 컴파일 시간에 물건을 통해 루프 내부에

그래서, 당신은 당신이에 대해 비교하려는 런타임 변수에 정기적 switch 명령문을 작성한다 할 일은,의 foreach를 넣어 너는 사업에 종사하고있어.

마찬가지로, mixin 문자열 대신이 __traits(getMember) 문자열을 사용하여 메서드를 호출했습니다. 이 솔루션은 이름 충돌을 피하는 데 도움이되며 IMO는 더 깨끗한 코드입니다. 원하는 경우 과부하를 처리 할 수도 있습니다 (__traits(getMember) 대신 __traits(getOverloads)이 있으면 각 매개 변수를 반복하고 매개 변수 유형을 일치시킬 수 있음).

마지막으로 을 다른 case 문 내에 중첩 할 수 있습니다. 바깥 쪽 루프 또는 switch을 벗어나 모호하지 않으려면 루프와 스위치에 레이블을 붙이고 break label_name_here;을 사용하여 중단 할 항목을 지정합니다. 중첩 루프가있는 continue의 경우에도 마찬가지입니다.

BTW std.traits 항목에 들어가면 string[]을 다른 유형의 인수로 변환하는 래퍼 함수를 ​​자동으로 생성 할 수도 있습니다. 나는 나의 책이 이미 꺼져 있었으면 좋겠다. 나는이 책에 대해 약간의 글을 썼다. 지금 당장 글을 쓰고 싶지는 않지만, 만약 당신이 그것을 시도하고 싶다면 같은 모듈에서 std.traits.ParameterTypeTupleReturnType을 보면된다. .