سؤال

وأنا تعثرت في الآونة الأخيرة على المشكلة التي تسببها بعض رمز قديم جدا كتبت الذي كان من الواضح على افتراض أن الإشارات واجهة المستخدم في بيان 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; 
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top