C# Ca2000: التخلص من الكائنات قبل فقد نطاقها باستخدام Filestream/XmlTexTreader

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

سؤال

لدي الكثير من الكود مثل هذا:

FileStream fs = File.Open(@"C:\Temp\SNB-RSS.xml", FileMode.Open); 
using (XmlTextReader reader = new XmlTextReader(fs)) 
{ 
   /* Some other code */
}

هذا يعطيني تحذير تحليل الكود التالي:

CA2000 : Microsoft.Reliability : In method 'SF_Tester.Run()', object 'fs' is not disposed along all exception paths. Call System.IDisposable.Dispose on object 'fs' before all references to it are out of scope.

إذا اتبعت الاقتراح ووضعت الملف. فتح في عبارة باستخدام ، أحصل على هذا:

CA2202 : Microsoft.Usage : Object 'fs' can be disposed more than once in method 'SF_Tester.Run()'. To avoid generating a System.ObjectDisposedException you should not call Dispose more than one time on an object.: Lines: 39

أنا أستخدم VS2010 ولا يسعني إلا أن أعتقد أنني أفعل شيئًا خاطئًا ولكني لا أراه. ما الخطأ الذي افعله؟

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

المحلول

تنهد ، مرهق أليس كذلك. تجنب كل هذا باستخدام طريقة إنشاء () الموصى بها:

 using (var reader = XmlReader.Create(@"C:\Temp\SNB-RSS.xml")) {
     //...
 }

نصائح أخرى

نظرًا لأن أحداً لم يقدم حلاً يحل هذه المشكلة حتى الآن ، فأنا أكتب حل عملي هنا:

FileStream fs = new FileStream(fileName, FileMode.Truncate, FileAccess.ReadWrite,    FileShare.ReadWrite);
try
{
   using (var fileWriter = new StreamWriter(fs, encoding))
   {
       fs = null;
       fileWriter.Write(content);
    }
 }
 finally
 {
     if (fs != null)
         fs.Dispose();
 }

هذا يزيل CA2000.

أنا فقط أخمن. ليس لديك وقت للذهاب من خلال تحليل كامل الآن.

لنفترض XmlTextReader تم تمرير مُنشئ المُنشئ ، وبالتالي التخلص من XmlTextReader سيتم أيضا Dispose الدفق الأساسي. هذا من شأنه أن يفسر السلوك الذي تراه. ربما XmlTextReader يمكن أن يرمي المنشئ ، وفي هذه الحالة التحذير الأصلي fs من المنطقي. ومع ذلك ، بالنظر إلى تلك الفرضية ، هذا الرمز

        var fs = File.Open(@"C:\Temp\SNB-RSS.xml", FileMode.Open);
        XmlTextReader reader = null;
        try
        {
            reader = new XmlTextReader(fs);
        }
        finally
        {
            if (reader== null)
            {
                fs.Dispose();
            }
        }
        if (reader != null)
        {
            using (reader)
            {
                /* Some other code */
            }
        }

هو ، على ما أعتقد ، صحيح ، ولكن لا يزال يحقق تحذيرا زائفة. هذا ينبعث منه رائحة مثال لطيف يوضح حدود أدوات التحليل الثابت.

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

إنها قضية معروفة

http://connect.microsoft.com/visualstudio/feedback/details/535118/ca2000-and-ca2202-offer-contradictory-warnings

إذا كنت تستخدم StreamWriter بدلاً من XmlTexTreader (كما في الحل أعلاه) ، فيمكنك استخدام طريقة مماثلة عبر المُنشئ ذي الصلة ؛ على سبيل المثال

var sw = new StreamWriter("filename.txt");

أو

var sw = new StreamWriter("filename.txt", /*append to file = */ false );

ليس من الواضح من الوثائق ما إذا كان النموذج الأول من المنشئ سيقوم بالكتابة أو إلحاق ملف.

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

إليك غلاف عام يفعل "بشكل صحيح" ، أي يعمل حول XmlReader المصمم بشكل سيء (ربما لم يكن من الممكن أن يكون قد استحوذ على التيار الذي يتلقاه؟ لست متأكدًا من الطريقة الصحيحة للقيام بذلك)

تنصل: لم يتم اختباره حقًا

public static TResult SafeNestedUsing<TOuter, TInner, TResult>(Func<TOuter> createOuterDisposable, Func<TOuter, TInner> createInnerDisposable, Func<TInner, TResult> body)
        where TInner : IDisposable
        where TOuter : class, IDisposable
    {
        TOuter outer = null;
        try
        {
            outer = createOuterDisposable();
            using (var inner = createInnerDisposable(outer))
            {
                var result = body(inner);
                outer = null;
                return result;
            }
        }
        finally
        {
            if (null != outer)
            {
                outer.Dispose();
            }
        }
    }

مثال الاستخدام:

SafeNestedUsing<MemoryStream, XmlReader, XmlDocument>(
    ()          => new MemoryStream(array),
    (memStream) => XmlReader.Create(memStream, xmlReaderSettings),
    (xmlReader) =>
    {
        XmlDocument xmlDoc = new XmlDocument();
        xmlDoc.Load(xmlReader);
        return xmlDoc;
    });

هذه هو صاخب تمامًا ، وقد تجادل بأنه من الأفضل تكرار نمط المحاولة/ضبطه/أخيرًا بدلاً من ذلك. لكن بالنسبة لنمط متكرر من الاستخدامات المتداخلة ، أفضل القيام بذلك بهذه الطريقة من تكرار الشيء الكامل في كل مرة.

فقط استخدم "استخدام" لـ Filestream

 using(FileStream fs = new FileStream(fileName, FileMode.Truncate, FileAccess.ReadWrite, FileShare.ReadWrite))
{
// some codes here

}

لا تقم بتعديل FS ولا تستخدم fs.close () داخل استخدام الأقواس المجعد.

استخدم ال using بيان أيضا على filestream نفسه تماما مثل على XMLTexTreader.

http://msdn.microsoft.com/en-us/library/system.io.filestream(vs.71).aspx.

GRZ ، كريس.

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