سؤال

ومنذ سؤالي من أمس ربما كان غير واضح تماما، وأنا لم تحصل على إجابة أردت، وسأحاول لصياغة ذلك بطريقة أكثر عمومية:

هل هناك طريقة لتنفيذ سلوك خاص على أساس النوع الفعلي من نوع عام مثيل إما باستخدام العبارات الشرطية explict أو استخدام نوع من التخصص؟ شبة الكود:

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)

وطعاما رأيت السؤال الآخر الخاص بك (رابط أنت لم إليها)، ولكن ما أنت <م> حقا تبحث عنه؟ بشكل عام، القيام بشيء مشروطا نوع أو typecode عبر استثناءات مثل تقومون به أو عموما أفضل تتحول التحول إلى وجود واجهة أو وظيفة مجردة في مكان ما أن يحصل على تطويعه من قبل السياق.

وTypeInfo (T) هو الطريق الصحيح. وعلاوة على ذلك يمكنك استخدام جميع الاشياء من وحدة TypInfo مثل سجل TTypeData لتحديد بعض خصائص محددة من النوع الذي تستخدمه بدلا من عام. عند تحديد نوع الحالي تستخدم بدلا من 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) الحصول على TypeInfo لT مع الدعائم العامة للT

2) الحصول TypeData لT مع الدعائم مفصلة لT

و3) استخدام مؤشر السحر للحصول على قيمة المعلمات نظرا اعتبارا من نوع T.

وهذا الأمل مساعدة.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top