دلفي: منذ متى والمراجع واجهة لم يعد صدر في نهاية كتلة معها؟
-
22-07-2019 - |
سؤال
وأنا تعثرت في الآونة الأخيرة على المشكلة التي تسببها بعض رمز قديم جدا كتبت الذي كان من الواضح على افتراض أن الإشارات واجهة المستخدم في بيان with
سيفرج عنه بمجرد ترك كتلة with
- نوع من مثل try-finally
كتلة الضمني (على غرار using
-بيان C # الصورة إذا فهمت بشكل صحيح).
وعلى ما يبدو (في دلفي 2009) هذا ليس (لم يعد؟) حالة. لا أحد يعرف متى حدث هذا؟ أو كان قانون بلدي مخطئة تماما لتبدأ؟
لتوضيح، وهنا مثال مبسط:
type
IMyIntf = interface;
TSomeObject = class(TInterfacedObject, IMyIntf)
protected
constructor Create; override; // creates some sort of context
destructor Destroy; override; // cleans up the context created in Create
public
class function GetMyIntf: IMyIntf; //a factory method, calling the constructor
end;
procedure TestIt;
begin
DoSomething;
with (TSomeObject.GetMyIntf) do
begin
DoStuff;
DoMoreStuff;
end; // <- expected: TSomeObject gets destroyed because its ref.count is decreased to 0
DoSomethingElse;
end; // <- this is where TSomeObject.Destroy actually gets called
وعندما بدأ شخص ما في القديم "with
عن المنكر" حجة هذا كان دائما مثال واحد كان يدور في خلدي الذي دفعني للاستمرار "نعم، ولكن ...". يبدو مثل كنت مخطئا ... هل يستطيع أحد تأكيد؟
المحلول
ووwith
الحفاظ كلمة في باسكال / دلفي يستخدم فقط للوصول بسهولة أعضاء السجلات أو الأشياء / الطبقات (أي لكي لا نذكر اسم السجل / الكائن / فئة ل). انها مختلفة جدا من C # with
التي تتعلق جمع القمامة. وقد وجدت في لغة باسكال منذ records
يوم ولدت، لتبسيط قانون يدعو لكثير من أعضاء البيانات (آنذاك يسمى ببساطة "حقول").
لتلخيص، with
له علاقة مع جمع القمامة، وإطلاق سراح من الذاكرة أو تدمير مثيلات الكائن لا شيء. الكائنات التي يتم بناؤها في رأس with
فقط يمكن أن تتم تهيئة في خط رمز منفصل من قبل، هو نفسه.
نصائح أخرى
لقد تغير هذا السلوك، مع أبدا. للوصول إلى سلوكك المتوقع يمكنك تغيير التعليمات البرمجية في هذه الطريقة:
procedure TestIt;
var
myIntf: IMyIntf;
begin
DoSomething;
myIntf := TSomeObject.GetMyIntf
DoStuff;
DoMoreStuff;
myIntf := nil; // <- here is where TSomeObject.Destroy called
DoSomethingElse;
end;
وأو يمكنك أن تفعل ذلك في إجراء:
procedure TestIt;
procedure DoAllStuff;
var
myIntf: IMyIntf;
begin
myIntf := TSomeObject.GetMyIntf
DoStuff;
DoMoreStuff;
end; // <- here is where TSomeObject.Destroy called
begin
DoSomething;
DoAllStuff;
DoSomethingElse;
end;