2016-06-21 2 views
1

У меня есть метод, который я пишу на C#, который принимает строку, которая содержит XML-документ, и массив потоков, которые являются XSD. Строка документа сверяются с XSDs:C#: Должны ли потоки быть закрыты/удалены в вызываемом методе?

private static XmlValidationResult ValidateDocumentInternal(string document, params Stream[] xsdStreams) 
{ 
    XmlReaderSettings settings = new XmlReaderSettings 
    { 
     ValidationType = ValidationType.Schema 
    }; 

    foreach (var xsdStream in xsdStreams) 
    { 
     using (xsdStream) 
     { 
      XmlReader xmlReader = XmlReader.Create(xsdStream); 

      try 
      { 
       settings.Schemas.Add(null, xmlReader); 
      } 
      finally 
      { 
       xmlReader.Close(); 
      } 
     } 
    } 

    var validationErrors = new List<string>(); 

    settings.ValidationEventHandler += (object sender, System.Xml.Schema.ValidationEventArgs e) => 
    { 
     validationErrors.Add($"({e.Exception.LineNumber}): {e.Message}"); 
    }; 

    using (var stream = document.ToStream()) 
    { 
     var reader = XmlReader.Create(stream, settings); 

     while (reader.Read()) 
     { 
     } 
    } 

    return new XmlValidationResult 
    { 
     Success = validationErrors.Count == 0, 
     ValidationErrors = validationErrors 
    }; 
} 

Мой вопрос, должен быть этот метод утилизации из XSD потоков или, что должно быть обязанностью вызывающей? Представьте себе следующий код, который проходит в документе и XSD и ожидает ValidateDocumentInternal распоряжаться поток XSD:

var document = GetDocument(); 
Stream xsd = GetXSD(); 
var validationResult = ValidateDocumentInternal(document, xsd); 

или он должен быть как (не утилизации потока в ValidateDocumentInternal):

var document = GetDocument(); 
using (Stream xsd = GetXSD()) { 
    var validationResult = = ValidateDocumentInternal(document, xsd); 
} 

или в качестве альтернативы я должен просто передать в bool о том, нужно ли распоряжаться или нет?

+3

Это может быть вопрос вкуса, но , лично я предпочел бы ваш второй вариант ('use'). – Heinzi

+1

Я всегда закрывал потоки в области, в которой они были созданы, поэтому, фактически, это отвечает за вызов вызывающего абонента, а не за то, что это происходит в черном ящике реализации метода. Тем не менее, некоторые API .net предлагают флаг, чтобы взять на себя ответственность за удаление ... вы также можете предложить это как необязательный параметр, который по умолчанию равен false. – spender

+1

Обычно я принимаю правило «Код, создающий поток, отвечает за его закрытие». Есть некоторые случаи, когда это неуместно, например, если это оставит поток открытым в течение очень долгого времени. Независимо от того, что вы делаете, важно документировать то, что делает вызывающий, с потоком - это относится к любому параметру, в котором вызывающий объект изменяет состояние поставленного объекта, но люди часто упускают из виду, что кто-то, читающий поток, меняет свое состояние. –

ответ

4

Я думаю, что это ответственность звонящего - это параметр, данный функцией от кого-то другого. Функция не может знать, используется ли она в другом контексте, и изменение, которое она будет делать, на самом деле является «побочным эффектом» ... я лично стараюсь избегать

+0

Это кажется вполне разумным на самом деле. Вы всегда можете установить позицию в потоке обратно на 0 и повторно использовать ее. –

+1

Может быть правдой, но это означает, что когда-либо код, который происходит после (или, что еще хуже, возможно, параллельно), эта функция должна знать, что функция имеет побочный эффект. Я думаю, что ваш второй вариант с использованием - лучшая практика. –

Смежные вопросы