كيفية الحصول على اسم الإجراء/الدالة الحالية في دلفي (كسلسلة)

StackOverflow https://stackoverflow.com/questions/2817699

  •  26-09-2019
  •  | 
  •  

سؤال

هل من الممكن الحصول على اسم الإجراء/الوظيفة الحالية كسلسلة ، ضمن إجراء/وظيفة؟ أفترض أنه سيكون هناك بعض "الماكرو" التي يتم توسيعها في وقت الترجمة.

السيناريو الخاص بي هو: لدي الكثير من الإجراءات التي يتم منحها سجلًا ويجب أن تبدأ جميعًا عن طريق التحقق من صحة السجل ، وبالتالي يتم نقل السجل إلى "إجراء التحقق". يثير إجراء التحقق من التحقق (نفس الإجراءات) استثناءً إذا كان السجل غير صالح ، وأريد أن تتضمن رسالة الاستثناء اسم إجراء التحقق ، ولكن اسم الوظيفة/الإجراء الذي يسمى المدقق الإجراء (بشكل طبيعي).

هذا هو ، لدي

procedure ValidateStruct(const Struct: TMyStruct; const Sender: string);
begin
 if <StructIsInvalid> then
    raise Exception.Create(Sender + ': Structure is invalid.');
end;

وثم

procedure SomeProc1(const Struct: TMyStruct);
begin
  ValidateStruct(Struct, 'SomeProc1');
  ...
end;

...

procedure SomeProcN(const Struct: TMyStruct);
begin
  ValidateStruct(Struct, 'SomeProcN');
  ...
end;

سيكون أقل عرضة للخطأ إذا تمكنت بدلاً من ذلك من كتابة شيء مثل

procedure SomeProc1(const Struct: TMyStruct);
begin
  ValidateStruct(Struct, {$PROCNAME});
  ...
end;

...

procedure SomeProcN(const Struct: TMyStruct);
begin
  ValidateStruct(Struct, {$PROCNAME});
  ...
end;

ثم في كل مرة يواجه فيها التحويل البرمجي {$ procname} ، فإنه ببساطة يحل محل "الماكرو" باسم الوظيفة/الإجراء الحالية كخيرية حرفية.

تحديث

المشكلة في النهج الأول هي أنه معرض للخطأ. على سبيل المثال ، يحدث بسهولة أنك تخطئ بسبب نسخ الزخار:

  procedure SomeProc3(const Struct: TMyStruct);
  begin
    ValidateStruct(Struct, 'SomeProc1');
    ...
  end;

أو الأخطاء المطبعية:

procedure SomeProc3(const Struct: TMyStruct);
begin
  ValidateStruct(Struct, 'SoemProc3');
  ...
end;

أو مجرد ارتباك مؤقت:

procedure SomeProc3(const Struct: TMyStruct);
begin
  ValidateStruct(Struct, 'SameProc3');
  ...
end;
هل كانت مفيدة؟

المحلول

نحن نفعل شيئًا مشابهًا ونعتمد فقط على اتفاقية: وضع أ مقدار ثابت SMethodName عقد اسم الوظيفة في البداية.
ثم جميع روتيننا تتبع نفس القالب, ، ونحن نستخدم هذا const في تأكيد وغيرها من استثناءات رفع.
بسبب قرب const مع الاسم الروتيني ، هناك فرصة ضئيلة أن تبقى خطأ مطبعي أو أي تباين هناك لفترة طويلة.
ymmv بالطبع ...

procedure SomeProc1(const Struct: TMyStruct);
const
  SMethodName = 'SomeProc1';
begin
  ValidateStruct(Struct, SMethodName);
  ...
end;

...

procedure SomeProcN(const Struct: TMyStruct);
const
  SMethodName = 'SomeProcN';
begin
  ValidateStruct(Struct, SMethodName);
  ...
end;

نصائح أخرى

أعتقد أن هذا نسخة مكررة من هذا السؤال: كيف تحصل على اسم الطريقة الحالية في دلفي 7؟

الإجابة هناك للقيام بذلك ، تحتاج إلى شكل من أشكال معلومات التصحيح في مشروعك ، واستخدام ، على سبيل المثال ، JCL وظائف لاستخراج المعلومات منه.

سأضيف أنني لم أستخدم دعم RTTI الجديد في D2009/2010 ، لكن لن يفاجئني إذا كان هناك شيء ذكي يمكنك القيام به به. على سبيل المثال ، هذا يوضح لك كيفية سرد جميع طرق الفصل, ، ويتم تمثيل كل طريقة بواسطة trttimethod. التي تنحدر من trttinamedObject التي لديها أ خاصية الاسم التي "تحدد اسم الكيان المنعكس". أنا متأكد من أنه يجب أن تكون هناك طريقة للحصول على إشارة إلى المكان الذي أنت فيه حاليًا ، أي الطريقة التي تتواجد بها حاليًا. هذا كله تخمين ، ولكن حاول إعطاء ذلك!

لا يوجد ماكرو لوقت التجميع ، ولكن إذا قمت بتضمين ما يكفي من معلومات التصحيح ، فيمكنك استخدام CallStack للعثور عليها. يرى هذا السؤال نفسه.

هناك طريقة أخرى لتحقيق التأثير وهي إدخال بيانات تعريف المصدر في تعليق خاص مثل

ValidateStruct(Struct, 'Blah'); // LOCAL_FUNCTION_NAME

ثم قم بتشغيل أداة طرف ثالث على مصدرك في حدث بناء مسبقًا للعثور على خطوط مع "local_function_name" في مثل هذا التعليق ، واستبدال جميع الحرفيين بالسلسلة باسم الطريقة التي يظهر فيها هذا الرمز ، بحيث على سبيل المثال الرمز يصبح

ValidateStruct(Struct, 'SomeProc3'); // LOCAL_FUNCTION_NAME

إذا كان سطر الكود داخل طريقة "SomeProc3". لن يكون من الصعب على الإطلاق كتابة مثل هذه الأداة في بيثون ، على سبيل المثال ، وسيكون استبدال النص الذي يتم في دلفي سهلاً بما فيه الكفاية أيضًا.

إن إجراء الاستبدال تلقائيًا يعني أنك لا تقلق أبدًا بشأن التزامن. على سبيل المثال ، يمكنك استخدام أدوات إعادة التجهيز لتغيير أسماء الطرق الخاصة بك ، ثم سيتم تحديث حرفي السلسلة تلقائيًا على ممر المترجم التالي.

شيء مثل المصدر المخصص قبل المعالج.

أعطيت هذا السؤال A +1 ، هذا موقف كان لدي عدة مرات من قبل ، وخاصة لرسائل فشل التأكيد. أعلم أن تتبع المكدس يحتوي على البيانات ، ولكن وجود الاسم الروتيني داخل رسالة التأكيد يجعل الأشياء أسهل قليلاً ، والقيام بذلك يدويًا يخلق خطر الرسائل التي لا معنى لها ، كما أشار OP.

تعديل: ال JcdDebug.pas يبدو أن الطرق الموضحة في الإجابات الأخرى أبسط بكثير من إجابتي ، شريطة أن تكون معلومات التصحيح موجودة.

لقد حللت مشاكل مماثلة من خلال التصميم. مثالك يربكني لأنك يبدو أنك تفعل ذلك بالفعل.

يمكنك لف وظائف التحقق من الصحة الخاصة بك مرة واحدة مثل هذا:

procedure SomeValidateProc3(const Struct: TMyStruct);
  begin
    ValidateStruct(Struct, 'SomeProc3');
  end;

ثم بدلاً من الاتصال مرارًا وتكرارًا:

ValidateStruct(Struct, 'SomeProc3");

أنت أتصل:

SomeValidateProc3(Struct);

إذا كان لديك خطأ مطبعي ، فسيقوم المترجم بالقبض عليه:

SoemValidateProc3(Struct);

إذا كنت تستخدم اسمًا أكثر جدوى لوظائف Wrapper مثل "ValidateName" ، يصبح الرمز أكثر قابلية للقراءة أيضًا.

أعتقد أنك تفعل ذلك بالطريقة الخاطئة: أولاً ، تحقق مما إذا كان هناك خطأ وعندها فقط (أي: أنت بحاجة إلى اسم المتصل) استخدم بعض الأدوات مثل JCldebug للحصول على اسم المتصل عن طريق تمرير الإرجاع عنوان من المكدس إلى ذلك.

يعد الحصول على اسم الإجراء أمرًا مكلفًا للغاية ، لذا فأنت تريد فقط القيام بذلك عند الضرورة للغاية.

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