2015-02-04 6 views
2

나는 바운드 형의 두 종류의 T 정수 및 문자열에 원하는 :델파이 제네릭 형 제약 순서 유형

interface 

type 
    MyFactory<T> = class 
    public 
    function createGenerator<T:Integer,string>:IGenerator<T>; 
    end; 

그러나 컴파일러는 제공 : '(..) E2510 유형'정수 '유효한 제약하지 않습니다 '. 유형 T를 정수 또는 문자열로 제한하려면 어떻게해야합니까? 또는 ordinal 형식을 사용하고 있기 때문에이 문제가 있습니까?

답변

8

델파이 제네릭은 서수 또는 문자열 유형 제약 조건을 지원하지 않습니다.

만 허용 제약이다

  • 0 개, 1 개, 또는 여러 인터페이스 유형
  • 제로 또는 하나의 클래스 유형을
  • 예약어 "생성자", "클래스", 또는 "기록"

Delphi Constraints in Generics

난 단지 당신이 accom하려고 정확히 추측 할 수 plish하지만 다음 코드는

IGenerator<T> = interface 
    function Generate: T; 
    end; 

    TStringGenerator = class(TInterfacedObject, IGenerator<string>) 
    public 
    function Generate: string; 
    end; 

    TIntegerGenerator = class(TInterfacedObject, IGenerator<integer>) 
    public 
    function Generate: integer; 
    end; 

    MyFactory<T> = class 
    public 
    class function createGenerator<T>: IGenerator<T>; 
    end; 

class function MyFactory<T>.createGenerator<T>: IGenerator<T>; 
var 
    gs: IGenerator<string>; 
    gi: IGenerator<integer>; 
begin 
    if TypeInfo(T) = TypeInfo(string) then 
    begin 
     gs := TStringGenerator.Create; 
     Result := IGenerator<T>(gs); 
    end 
    else 
    if TypeInfo(T) = TypeInfo(integer) then 
    begin 
     gi := TIntegerGenerator.Create; 
     Result := IGenerator<T>(gi); 
    end 
    else Result := nil; 
end; 

function TIntegerGenerator.Generate: integer; 
begin 
    Result := 10; 
end; 

function TStringGenerator.Generate: string; 
begin 
    Result := 'abc'; 
end; 

var 
    i: integer; 
    s: string; 

    i := MyFactory<integer>.createGenerator<integer>.generate; 
    s := MyFactory<string>.createGenerator<string>.generate; 

TTypeKind도 유형을 결정하는 대신 TypeInfo 사용할 수 있습니다 몇 가지 아이디어를 당신에게 제공 할 수 있습니다. 주요 차이점은 TypeInfo은 정확한 유형을 사용하고, TTypeKind은 특정 카테고리에 속하는 모든 유형을 포함한다는 것입니다. TTypeKind은 더 많은 유연성을 제공하지만 코드가 타입 변환에 의존하는 경우에는주의해서 사용해야합니다. 예를 들어 tkIntegerintegerbyte 유형을 모두 포함하며, 유형 변환은 오류를 유발할 수 있습니다.

class function MyFactory<T>.createGenerator<T>: IGenerator<T>; 
var 
    gs: IGenerator<string>; 
    gi: IGenerator<integer>; 
begin 
    case PTypeInfo(TypeInfo(T)).Kind of 
    tkUString : 
     begin 
     gs := TStringGenerator.Create; 
     Result := IGenerator<T>(gs); 
     end; 
    tkInteger : 
     begin 
     gi := TIntegerGenerator.Create; 
     Result := IGenerator<T>(gi); 
     end 
    else Result := nil; 
    end; 
end; 
+0

@TLama 그렇습니다. 그것은 그 대답이 지금 언어에 의해 능가되었다는 것을 독자가 알게 할 것입니다. 특정 버전에 링크하면 (그리고 원래 버전이 XE7 인 현재 버전이 아닌 XE6에 링크되어 있기 때문에 편집 한 경우) 향후 독자는 그러한 개발을 발견 할 수있는 기회를 놓치게됩니다. –

+0

'GetTypeKind'가 더 적절할 것 같습니다. –

+0

@David는 코드에 따라 다릅니다. 'TypeInfo'는 정확한 타입을 제공하며, 이는 나의 예제에서 타입 캐스팅에 중요합니다. –