هل هناك أفضل حتمية التخلص من نمط من المتداخلة "باستخدام"s ؟

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

  •  09-06-2019
  •  | 
  •  

سؤال

في C#, إذا كنت تريد أن deterministically تنظيف غير المدارة الموارد يمكنني استخدام "باستخدام" الكلمة.ولكن للعديد من الكائنات تعتمد هذا ينتهي التعشيش أخرى:

using (FileStream fs = new FileStream("c:\file.txt", FileMode.Open))
{
    using (BufferedStream bs = new BufferedStream(fs))
    {
        using (StreamReader sr = new StreamReader(bs))
        {
            // use sr, and have everything cleaned up when done.
        }
    }
}

في C++, اعتدت أن أكون قادرا على استخدام destructors أن تفعل ذلك من هذا القبيل:

{    
    FileStream fs("c:\file.txt", FileMode.Open);
    BufferedStream bs(fs);
    StreamReader sr(bs);
    // use sr, and have everything cleaned up when done.
}

هل هناك طريقة أفضل في C# أن تفعل هذا ؟ أو أنا عالقة مع مستويات متعددة من التعشيش?

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

المحلول

لا يجب أن عش مع عدة usings:

using (FileStream fs = new FileStream("c:\file.txt", FileMode.Open))
using (BufferedStream bs = new BufferedStream(fs))
using (StreamReader sr = new StreamReader(bs))
{
    // all three get disposed when you're done
}

نصائح أخرى

يمكنك وضع استخدام البيانات معا قبل افتتاح الأقواس مثل ذلك:

  using (StreamWriter w1 = File.CreateText("W1"))
  using (StreamWriter w2 = File.CreateText("W2"))
  {
      // code here
  }

http://blogs.msdn.com/ericgu/archive/2004/08/05/209267.aspx

يمكنك استخدام بناء الجملة هذا أن تتكثف الأمور قليلا:

using (FileStream fs = new FileStream("c:\file.txt", FileMode.Open))
using (BufferedStream bs = new BufferedStream(fs))
using (StreamReader sr = new StreamReader(bs))
{
}

هذا هو واحد من تلك المناسبات النادرة حيث لا تستخدم { } لجميع الكتل المنطقي IMHO.

بدلا من أن تعشش في استخدام البيانات يمكنك فقط كتابة .التخلص المكالمات يدويا ولكن عليك شبه المؤكد أن يغيب واحد في بعض نقطة.

تشغيل إما التقدم أو أي شيء آخر يمكن التأكد من أن جميع IDisposable-تنفيذ نوع الحالات لديهم .Dispose() المكالمة ، أو التعامل مع التعشيش.

لقد نفذت الحلول مثل مايكل المروج'ق من قبل ، ولكن له StreamWrapper رمز لا تأخذ في الاعتبار إذا كان Dispose() أساليب دعا عضو المتغيرات رمي استثناء لسبب أو آخر ، اللاحقة Dispose()es لن يتم استدعاء والموارد يمكن أن تتدلى.على طريقة أكثر أمانا على هذا العمل هو:

        var exceptions = new List<Exception>();

        try
        {
            this.sr.Dispose();
        }
        catch (Exception ex)
        {
            exceptions.Add(ex);
        }

        try
        {
            this.bs.Dispose();
        }
        catch (Exception ex)
        {
            exceptions.Add(ex);
        }

        try
        {
            this.fs.Dispose();
        }
        catch (Exception ex)
        {
            exceptions.Add(ex);
        }

        if (exceptions.Count > 0)
        {
            throw new AggregateException(exceptions);
        }
    }

يمكنك حذف الأقواس المتعرجة ، مثل:

using (FileStream fs = new FileStream("c:\file.txt", FileMode.Open))
using (BufferedStream bs = new BufferedStream(fs))
using (StreamReader sr = new StreamReader(bs))
{
        // use sr, and have everything cleaned up when done.
}

أو استخدام العادية حاول أخيرا النهج:

FileStream fs = new FileStream("c:\file.txt", FileMode.Open);
BufferedStream bs = new BufferedStream(fs);
StreamReader sr = new StreamReader(bs);
try
{
        // use sr, and have everything cleaned up when done.
}finally{
   sr.Close(); // should be enough since you hand control to the reader
}

وهذا يجعل أكبر بكثير صافي زائد في الأسطر من التعليمات البرمجية ، ولكن المكاسب الملموسة في القراءة:

using (StreamWrapper wrapper = new StreamWrapper("c:\file.txt", FileMode.Open))
{
    // do stuff using wrapper.Reader
}

حيث StreamWrapper ويعرف هنا:

private class StreamWrapper : IDisposable
{
    private readonly FileStream fs;
    private readonly BufferedStream bs;
    private readonly StreamReader sr;

    public StreamWrapper(string fileName, FileMode mode)
    {
        fs = new FileStream(fileName, mode);
        bs = new BufferedStream(fs);
        sr = new StreamReader(bs);
    }

    public StreamReader Reader
    {
        get { return sr; }
    }

    public void Dispose()
    {
        sr.Dispose();
        bs.Dispose();
        fs.Dispose();
    }
}

مع بعض الجهد ، StreamWrapper يمكن ريفاكتوريد أن يكون أكثر عمومية و قابلة لإعادة الاستخدام.

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

using (Stream Reader sr = new StreamReader( new BufferedStream( new FileStream("c:\file.txt", FileMode.Open))))
{
    // all three get disposed when you're done
}

على سبيل المثال دعونا نفترض أن لديك:

ملف اسمه 1.xml تحت c:\

مربع نص اسمه textBox1 مع خط متعدد الخصائص تعيين على.

const string fname = @"c:\1.xml";

StreamReader sr=new StreamReader(new BufferedStream(new FileStream(fname,FileMode.Open,FileAccess.Read,FileShare.Delete)));
textBox1.Text = sr.ReadToEnd();

استخدام العبارة النحوية السكر الذي يحول إلى:

   try
   {
      obj declaration
      ...
   }
   finally
   {
      obj.Dispose();
   }

يمكنك بشكل صريح استدعاء التصرف في الأشياء الخاصة بك ، لكنها لن تكون آمنة لأنه إذا كان واحد منهم يطرح استثناء الموارد لن يتحرر بشكل صحيح.

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