개인적으로 저는 Move
으로 전화를 걸어 이것을 할 것입니다. 나는 다음과 같은 유형이 있습니다
type
TEnumeration<T: record> = class
strict private
class function TypeInfo: PTypeInfo; inline; static;
class function TypeData: PTypeData; inline; static;
public
class function IsEnumeration: Boolean; static;
class function ToOrdinal(Enum: T): Integer; inline; static;
class function FromOrdinal(Value: Integer): T; inline; static;
class function MinValue: Integer; inline; static;
class function MaxValue: Integer; inline; static;
class function InRange(Value: Integer): Boolean; inline; static;
class function EnsureRange(Value: Integer): Integer; inline; static;
end;
{ TEnumeration<T> }
class function TEnumeration<T>.TypeInfo: PTypeInfo;
begin
Result := System.TypeInfo(T);
end;
class function TEnumeration<T>.TypeData: PTypeData;
begin
Result := TypInfo.GetTypeData(TypeInfo);
end;
class function TEnumeration<T>.IsEnumeration: Boolean;
begin
Result := TypeInfo.Kind=tkEnumeration;
end;
class function TEnumeration<T>.ToOrdinal(Enum: T): Integer;
begin
Assert(IsEnumeration);
Assert(SizeOf(Enum)<=SizeOf(Result));
Result := 0; // needed when SizeOf(Enum) < SizeOf(Result)
Move(Enum, Result, SizeOf(Enum));
Assert(InRange(Result));
end;
class function TEnumeration<T>.FromOrdinal(Value: Integer): T;
begin
Assert(IsEnumeration);
Assert(InRange(Value));
Assert(SizeOf(Result)<=SizeOf(Value));
Move(Value, Result, SizeOf(Result));
end;
class function TEnumeration<T>.MinValue: Integer;
begin
Assert(IsEnumeration);
Result := TypeData.MinValue;
end;
class function TEnumeration<T>.MaxValue: Integer;
begin
Assert(IsEnumeration);
Result := TypeData.MaxValue;
end;
class function TEnumeration<T>.InRange(Value: Integer): Boolean;
var
ptd: PTypeData;
begin
Assert(IsEnumeration);
ptd := TypeData;
Result := Math.InRange(Value, ptd.MinValue, ptd.MaxValue);
end;
class function TEnumeration<T>.EnsureRange(Value: Integer): Integer;
var
ptd: PTypeData;
begin
Assert(IsEnumeration);
ptd := TypeData;
Result := Math.EnsureRange(Value, ptd.MinValue, ptd.MaxValue);
end;
ToOrdinal
방법은 당신이 필요하지, 나는 당신이 당신의 클래스에 적응 할 수 있습니다 확신합니다.
이런 식으로 Move
을 사용하고 싶지 않다면 TValue
을 사용할 수 있습니다.
TValue.From<TKey>(Key).AsOrdinal
그리고 @TLama는 TValue
제네릭 및 RTTI의 기풍과 유지에 더 많은 것 같다 사용하여, 그것의 얼굴에
TValue.From<TKey>(Key).ToString
를 사용하여 모든 GetEnumName
를 호출 피할 수 있다고 지적 . Move
에 대한 호출은 열거 형의 특정 구현 세부 정보를 사용합니다. 그러나 디버거를 단계별로 실행하고 꽤 많은 코드가 TValue.From<TKey>(Key).AsOrdinal
과 관련되어 있는지 관찰하는 것은 매우 흥미 롭습니다. 그것만으로도 TValue
을 사용하는 것이 좋습니다.
는 그러나 이것을 달성하는 또 다른 방법은
TRttiEnumerationType
를 사용하는 것입니다 :이의
TRttiEnumerationType.GetName<TKey>(Key)
구현은 훨씬 더 효율적으로, TValue.ToString
를 사용 GetEnumName
로 전화보다는 조금 더 많은 것보다입니다.
당신의 편집에 관한 것은, 내가 생산 코드에서 그 좋을 것 그것 내 대답에서'ToOrdinal','FromOrdinal'과 같은 정적 클래스 메소드를 추가하는 것이 더 깔끔합니다. 그들은 당신이'Result : = GetEnumName (System.TypeInfo (TKey), ToOrdinal (Key));'와 같이'ToString' 메소드를 작성할 수 있도록 허용 할 것이므로이 상위 메소드를 지역 변수로 오염시키지 말고'Move' . –
이동 명령 *을 사용해야한다고 생각하지 않습니다. 의도 된 방법은 'TValue'관련 코드를 사용하는 것입니다. 'TValue. (Key) .AsInteger'에서 말하고 싶습니다. –
TLama
@TLama 그 결과'EInvalidCast'가 나타납니다. –