2009-11-03 4 views
4

유형 이름을 포함하는 텍스트 문자열이 주어지면 적절한 유형 자체를 가져올 수있는 방법이 있습니까?RTTI : 이름으로 유형을 얻을 수 있습니까?

나는 이런 식으로 뭔가를 찾고 있어요 :

type 
    TSomeType<T> = class 
    // yadda yadda 
    end; 

procedure DoSomething; 
var 
    obj : TObject; 
begin 
    o := TSomeType<GetTypeByName('integer')>.Create; 
    // do stuff with obj 
end; 

나는 온라인으로 여러 RTTI의 설명에 고개 보았다 델파이 유닛을 통해 내가 무엇을 찾고 표시되지 않습니다했습니다. 이것이 가능한가?

+0

내가 만든 개체로 어떤 종류의 "물건"을 기대하십니까? –

+0

인터페이스를 가져옵니다. 그것은 지속성 계획의 일부입니다. – TrespassersW

+0

누가 당신이 "잡을 수있는"인터페이스를 가지고 있다고 말합니까? 특정 인터페이스를 구현한다는 것을 아는 유형에 대해 충분히 알고 있다면 위의 코드 스 니펫이 수행하는 작업을 수행 할 필요가 없다는 것을 충분히 알고 있습니다. –

답변

7

아니요, generics는 전적으로 compiletime입니다.

+0

글쎄, crud. 당신 말이 맞아 보이는군요. 그것은 내가 가지고 있었던 매우 멋진 생각을 싹 트게한다. 정보 주셔서 감사합니다. – TrespassersW

+0

이름에서 유형을 가져올 수있는 방법이 있는지 궁금하다. 비록 내가 원했던대로 그것을 정확하게 사용할 수 없더라도. – TrespassersW

5

언제든지 유형을 레지스트리 (문자열 목록 또는 사전으로 관리)에 등록하고 팩토리 함수를 만들어 적절한 객체를 반환 할 수 있습니다. 불행하게도 필요한 유형을 미리 알아야합니다. 델파이 함수는 RegisterClass와 FindClass를 클래스 유닛과 유사하게 사용합니다. 내 생각은 일반 템플릿 유형을 목록에 직접 넣는 것입니다.

가능한 사용의 예 :

RegisterCustomType('Integer',TSomeType<Integer>); 
RegisterCustomType('String',TSomeType<String>); 

if FindCustomType('Integer') <> nil then 
    O := FindCustomType('Integer').Create; 

편집 : 여기에 ... 나는 도움으로이 추출 레지스트리 저장을 처리하기 위해 Generics.Collections를에서 tDictionary를 사용하여 특정 간단한 구현을 떠날 것입니다 방법은 독자를위한 간단한 운동으로.

var 
    o : TObject; 
begin 
    TypeDict := TDictionary<String,TClass>.Create; 
    TypeDict.Add('integer',TList<integer>); 
    if TypeDict.ContainsKey('integer') then 
    o := TypeDict.Items['integer'].Create; 
    if Assigned(o) then 
    ShowMessage(o.ClassName); 
end; 

또 다른 편집

: 나는 지난 밤이 몇 가지 생각주고, 당신이이 개념에 병합 할 수있는 또 다른 방법을 발견했다. 인터페이스. 여기에 빠른 할 아무것도 예,하지만 쉽게 확장 할 수 있습니다 물론

TYPE 
    ITest = interface 
    ['{0DD03794-6713-47A0-BBE5-58F4719F494E}'] 
    end; 

    TIntfList<t> = class(TList<T>,ITest) 
    public 
    function QueryInterface(const IID: TGUID; out Obj): HRESULT; stdcall; 
    function _AddRef: Integer; stdcall; 
    function _Release: Integer; stdcall; 
    end; 

procedure TForm1.Button7Click(Sender: TObject); 
var 
    o : TObject; 
    fTestIntf : ITest; 
begin 
    TypeDict := TDictionary<String,TClass>.Create; 
    TypeDict.Add('integer',TIntfList<integer>); 
    if TypeDict.ContainsKey('integer') then 
    o := TypeDict.Items['integer'].Create; 
    if Assigned(o) and Supports(o,ITest,fTestIntf) then 
    ShowMessage(o.ClassName); 
end; 

당신의 QueryInterface, _AddRef 및 _Release 메소드를 구현하고 더 유용한 일을하기 위해 인터페이스를 확장해야합니다.

+0

감사합니다. 그게 제가 한 일입니다. 델피의 TPersistent에서 아이디어를 얻었습니다. 그리고 당신의 제안은 우리가 이미 생각해내는 (각 템플릿 유형을 등록하는 것) 것이고 그것은 정상적으로 작동합니다. 좀 더 유연하고 역동적 인 무언가를 기대했지만, 나는 그것을 얻으려고하는 것처럼 보이지 않습니다. 다시 한번 감사드립니다. – TrespassersW

+0

이것은 쉽게 유연하고 동적으로 만들 수 있습니다. 당신이 할 수없는 유일한 방법은 계획하지 않은 유형을 처리하는 것입니다. – skamradt

0

generics 및 기본 유형을 잊어 버린 경우 "RegisterClass"기능이 유용합니다. 그러나 제네릭이나 기본 유형에서는 작동하지 않습니다.

5

Delphi 2010의 새로운 RTTI 단위에는 유닛의 인터페이스 섹션에 선언 된 유형을 검색하는 방법이 있습니다. TRttiType 인스턴스로 표시되는 특정 유형의 경우 TRttiType.QualifiedName 속성은 나중에 유형을 검색하기 위해 TRttiContext.FindType과 함께 사용할 수있는 이름을 반환합니다. 정규화 된 이름은 전체 단위 이름 (존재하는 경우 네임 스페이스 포함)이고 '.'다음에 전체 유형 이름 (중첩 된 경우 외부 유형 포함)이옵니다.

그래서 context.FindType('System.Integer')으로 정수 유형 표현 (TRttiType 형태로)을 검색 할 수 있습니다.

그러나이 메커니즘은 컴파일 타임에 인스턴스화되지 않은 제네릭 형식의 인스턴스화를 검색하는 데 사용할 수 없습니다. 런타임에 인스턴스화하려면 런타임 코드 생성이 필요합니다.

+0

굉장! 정보 주셔서 감사합니다. – TrespassersW