سؤال

مرحبا، ما هي أفضل طريقة للقيام بمحاولة متداخلة وأخيرا البيانات في دلفي؟

var cds1  : TClientDataSet;
    cds2  : TClientDataSet;
    cds3  : TClientDataSet;
    cds4  : TClientDataSet;
begin
  cds1      := TClientDataSet.Create(application );
  try
    cds2      := TClientDataSet.Create(application );
    try
      cds3      := TClientDataSet.Create(application );
      try
        cds4      := TClientDataSet.Create(application );
        try
        ///////////////////////////////////////////////////////////////////////
        ///      DO WHAT NEEDS TO BE DONE
        ///////////////////////////////////////////////////////////////////////
        finally
          cds4.free;
        end;

      finally
        cds3.free;
      end;
    finally
      cds2.free;
    end;
  finally
    cds1.free;
  end;
end;

هل يمكنك اقتراح طريقة أفضل للقيام بذلك؟

هل كانت مفيدة؟

المحلول

ماذا عن ما يلي:

var cds1  : TClientDataSet;
    cds2  : TClientDataSet;
    cds3  : TClientDataSet;
    cds4  : TClientDataSet;
begin
  cds1      := Nil;
  cds2      := Nil;
  cds3      := Nil;
  cds4      := Nil;
  try
    cds1      := TClientDataSet.Create(nil);
    cds2      := TClientDataSet.Create(nil);
    cds3      := TClientDataSet.Create(nil);
    cds4      := TClientDataSet.Create(nil);
    ///////////////////////////////////////////////////////////////////////
    ///      DO WHAT NEEDS TO BE DONE
    ///////////////////////////////////////////////////////////////////////
  finally
    freeandnil(cds4);
    freeandnil(cds3);
    freeandnil(cds2);
    freeandnil(Cds1);
  end;
end;

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

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

تعديل تنظيف بعض الشيء بفضل التعليقات mghie. و utku..

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

نصائح أخرى

كنت أستخدم شيئا مثل هذا:

var
  Safe: IObjectSafe;
  cds1 : TClientDataSet;
  cds2 : TClientDataSet;
  cds3 : TClientDataSet;
  cds4 : TClientDataSet;
begin
  Safe := ObjectSafe;
  cds1 := Safe.Guard(TClientDataSet.Create(nil)) as TClientDataSet;
  cds2 := Safe.Guard(TClientDataSet.Create(nil)) as TClientDataSet;
  cds3 := Safe.Guard(TClientDataSet.Create(nil)) as TClientDataSet;
  cds4 := Safe.Guard(TClientDataSet.Create(nil)) as TClientDataSet;
  ///////////////////////////////////////////////////////////////////////
  ///      DO WHAT NEEDS TO BE DONE
  ///////////////////////////////////////////////////////////////////////

  // if Safe goes out of scope it will be freed and in turn free all guarded objects
end;

لتنفيذ الواجهة هذه مقال، ولكن يمكنك بسهولة إنشاء شيء مماثل لنفسك.

تعديل:

لقد لاحظت أن ذلك في حارس المقال المرتبط () إجراء. في التعليمات البرمجية الخاصة بي، لدي وظائف الحرس المثقلة () التي عودة TOBJECT، فوق نموذج التعليمة البرمجية يفترض شيئا مشابها. بالطبع مع Generic Code أفضل بكثير ممكن الآن ...

تحرير 2:

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

هناك تباين آخر للرمز دون محاولة متداخلة ... وأخيرا حدث فقط لي. إذا لم تقم بإنشاء المكونات مع المعلمة Aowner للمشكلات التي تم تعيينها إلى NIL، فيمكنك ببساطة الاستفادة من إدارة العمر الذي يمنحك VCL مجانا:

var
  cds1: TClientDataSet;
  cds2: TClientDataSet;
  cds3: TClientDataSet;
  cds4: TClientDataSet;
begin
  cds1 := TClientDataSet.Create(nil);
  try
    // let cds1 own the other components so they need not be freed manually
    cds2 := TClientDataSet.Create(cds1);
    cds3 := TClientDataSet.Create(cds1);
    cds4 := TClientDataSet.Create(cds1);

    ///////////////////////////////////////////////////////////////////////
    ///      DO WHAT NEEDS TO BE DONE
    ///////////////////////////////////////////////////////////////////////

  finally
    cds1.Free;
  end;
end;

أنا مؤمن كبير في الرمز الصغير (إذا لم يكن مضايقا جدا).

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

function SafeFreeAndNil(AnObject: TObject): Boolean;
begin
  try
    FreeAndNil(AnObject);
    Result :=  True;
  except
    Result := False;
  end;
end;

var cds1  : TClientDataSet;
    cds2  : TClientDataSet;
    IsOK1 : Boolean;
    IsOK2 : Boolean;
begin
  cds1      := Nil;
  cds2      := Nil; 
 try
    cds1      := TClientDataSet.Create(nil);
    cds2      := TClientDataSet.Create(nil);    
    ///////////////////////////////////////////////////////////////////////
    ///      DO WHAT NEEDS TO BE DONE
    ///////////////////////////////////////////////////////////////////////
  finally
    IsOk2 := SafeFreeAndNil(cds2);    // an error in freeing cds2 won't stop execution
    IsOK1 := SafeFreeAndNil(Cds1);
    if not(IsOk1 and IsOk2) then
      raise EWhatever....
  end;
end;

هناك فيديو جيد استثناءات في الصانعين والمدمرين

يظهر بعض الأمثلة الجميلة مثل:

var cds1  : TClientDataSet;
    cds2  : TClientDataSet;
begin
  cds1      := Nil;
  cds2      := Nil; 
 try
    cds1      := TClientDataSet.Create(nil);
    cds2      := TClientDataSet.Create(nil);    
    ///////////////////////////////////////////////////////////////////////
    ///      DO WHAT NEEDS TO BE DONE
    ///////////////////////////////////////////////////////////////////////
  finally
    freeandnil(cds2);    //// what has if there in an error in the destructor of cds2
    freeandnil(Cds1);
  end;
end;

ماذا لو كان هناك في خطأ في المدمر للأكياس CDS2

لن يتم تدمير CDS1

تعديل

مورد جيد آخر هو:

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

mghie: حصلت دلفي على كائنات مخصصة

type
  TMyObject = object
  private
    FSomeField: PInteger;
  public
    constructor Init;
    destructor Done; override;
  end;

constructor TMyObject.Init;
begin
  inherited Init;
  New(FSomeField);
end;

destructor TMyObject.Done;
begin
  Dispose(FSomeField);
  inherited Done;
end;

var
  MyObject: TMyObject;

begin
  MyObject.Init;
  /// ...
end;

لسوء الحظ، كما يظهر المثال أعلاه: الكائنات المخصصة للمكدسة لا تمنع تسرب الذاكرة.

لذلك سيظل هذا دعوة إلى المدمر مثل هذا:

var
  MyObject: TMyObject;

begin
  MyObject.Init;
  try
    /// ...
  finally
    MyObject.Done;
  end;
end;

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

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