문제

내 질문 이후 어제 아마도 완전히 명확하지 않았고 내가 원하는 대답을 얻지 못했습니다. 나는 더 일반적인 방식으로 그것을 공식화하려고 노력할 것입니다.

실용적 진술을 사용하거나 어떤 종류의 전문화를 사용하는 실제 유형의 인스턴스화 된 일반 유형을 기반으로 특수 행동을 구현할 수있는 방법이 있습니까? 의사 코드 :

TGenericType <T> = class
  function Func : Integer;
end;
...
function TGenericType <T>.Func : Integer;
begin
  if (T = String) then Exit (0);
  if (T is class) then Exit (1);
end;
...
function TGenericType <T : class>.Func : Integer;
begin
Result := 1;
end;
function TGenericType <String>.Func : Integer;
begin
Result := 0;
end;
도움이 되었습니까?

해결책

사용하여 RTTI로 돌아갈 수 있습니다 TypeInfo(T) = TypeInfo(string). 무언가가 수업인지 테스트하려면 다음과 같은 것을 사용할 수 있습니다. PTypeInfo(TypeInfo(T))^.Kind = tkClass.

그만큼 PTypeInfo 유형 및 tkClass 열거 회원은 TypInfo 단위.

다른 팁

누군가 내가 "현으로 특별한 치료법으로 최악의 크기"를 구현 한 방법에 관심이 있다면

class function RTTIUtils.GetDeepSize <T> (Variable : T) : Integer;
var
  StringLength          : Integer;
  Ptr                   : PInteger;
begin
if (TypeInfo (T) = TypeInfo (String)) then
  begin
  Ptr := @Variable;
  Ptr := PInteger (Ptr^);
  Dec (Ptr);
  StringLength := Ptr^;
  Result := StringLength * SizeOf (Char) + 12;
  end
else
  Result := 0;
end;

나를 위해, 이것은 당면한 일을합니다. 모든 기고자들에게 감사합니다!

C#에서는 할 수 있습니다 typeof(T) 당신이 같은 일을 할 수 있습니다

(T = String)

또는

(T is class)

나는 당신의 다른 질문을 보지 못했습니다 (당신은 그것에 연결되지 않았습니다), 당신은 무엇입니까? 진짜 찾고있는? 일반적으로, 수행중인 IFS 또는 스위치를 통해 유형 또는 타이프 코드에서 조건부를 수행하는 것은 일반적으로 컨텍스트에 의해 사용자 정의되는 어딘가에 인터페이스 또는 추상 기능을 갖도록 가장 잘 변환됩니다.

TypeInfo (t)는 올바른 방법입니다. 또한 ttypedata 레코드와 같은 TypInfo 장치의 모든 물건을 사용하여 일반 대신 사용하는 유형의 특정 속성을 결정할 수 있습니다. t 대신 사용 된 현재 유형을 결정하면 포인터 트릭을 사용하여 변수 값을 얻을 수 있습니다.

다음은 열거 유형을 일반적인 것으로 받아들이는 샘플 코드입니다. 일반적인 열거에 대해서만 작동합니다 (고정 값없이

tenumwontwork = (첫 번째 = 1, 두 번째, 셋째)

) 그리고 열거는 절차 내에서 로컬 유형으로 선언해서는 안됩니다. 이 경우 컴파일러는 열거에 대한 typeinfo를 생성하지 않습니다.

type
  // Sample generic class that accepts any enumeration type as T
  TEnumArr<T> = class
  strict private
    fArr: array of Byte;
    fIdxType: TOrdType;
    function IdxToInt(idx: T): Int64;
    procedure Put(idx: T; Val: Byte);
    function Get(idx: T): Byte;
  public
    constructor Create;
    property Items[Index: T]: Byte read Get write Put; default;
  end;

constructor TEnumArr<T>.Create;
var
  pti: PTypeInfo;
  ptd: PTypeData;
begin
  pti := TypeInfo(T);
  if pti = nil then
    Error('no type info');
  // Perform run-time type check
  if pti^.Kind <> tkEnumeration then
    Error('not an enum');
  // Reach for TTypeData record that goes right after TTypeInfo record
  // Note that SizeOf(pti.Name) won't work here
  ptd := PTypeData(PByte(pti) + SizeOf(pti.Kind) + (Length(pti.Name)+1)*SizeOf(AnsiChar));
  // Init internal array with the max value of enumeration
  SetLength(fArr, ptd.MaxValue);
  // Save ordinal type of the enum
  fIdxType := ptd.OrdType;
end;

// Converts index given as enumeration item to integer.
// We can't just typecast here like Int64(idx) because of compiler restrictions so
//  use pointer tricks. We also check for the ordinal type of idx as it may vary
//  depending on compiler options and number of items in enumeration.
function TEnumArr<T>.IdxToInt(idx: T): Int64;
var
  p: Pointer;
begin
  p := @idx;

  case fIdxType of
    otSByte: Result := PShortInt(p)^;
    otUByte: Result := PByte(p)^;
    otSWord: Result := PSmallInt(p)^;
    otUWord: Result := PWord(p)^;
    otSLong: Result := PLongInt(p)^;
    otULong: Result := PLongWord(p)^;
  end;
end;

function TEnumArr<T>.Get(idx: T): Byte;
begin
  Result := fArr[IdxToInt(idx)];
end;

procedure TEnumArr<T>.Put(idx: T; Val: Byte);
begin
  fArr[IdxToInt(idx)] := Val;
end;

사용 샘플 :

type
  TEnum  = (enOne, enTwo, enThree);
var
  tst: TEnumArr<TEnum>;
begin
  tst := TEnumArr<TEnum>.Create;
  tst[enTwo] := $FF;
  Log(tst[enTwo]);

이력서로서 나는 여기에 세 가지 트릭을 사용했습니다.

1) T의 일반 소품으로 t에 대한 typeinfo 받기

2) T의 상세한 소품으로 t에 대한 typedata 받기

3) 포인터 마법을 사용하여 T 형에서 주어진 매개 변수의 값을 얻습니다.

이 도움을 바랍니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top