2013-12-18 1 views
9

Я делал рефакторинг класса и думал о перемещении 100 строк в отдельном методе. Как это:IDisposable objects как ref param для метода

using iTextSharp.text; 
using iTextSharp.text.pdf; 

class Program 
{ 
    private static void Main(string[] args) 
    { 
     Document doc = new Document(iTextSharp.text.PageSize.LETTER, 10, 10, 42, 35); 
     using (var mem = new MemoryStream()) 
     { 
      using (PdfWriter wri = PdfWriter.GetInstance(doc, mem)) 
      { 
       doc.Open(); 
       AddContent(ref doc, ref wri); 
       doc.Close(); 
       File.WriteAllBytes(@"C:\testpdf.pdf", mem.ToArray()); 
      } 
     } 
    } 

    public static void AddContent(ref Document doc, ref PdfWriter writer) 
    { 
     var header = new Paragraph("My Document") { Alignment = Element.ALIGN_CENTER }; 
     var paragraph = new Paragraph("Testing the iText pdf."); 
     var phrase = new Phrase("This is a phrase but testing some formatting also. \nNew line here."); 
     var chunk = new Chunk("This is a chunk."); 
     doc.Add(header); 
     doc.Add(paragraph); 
     doc.Add(phrase); 
     doc.Add(chunk); 

    } 
} 

При вызове метода компилятор бросает исключение: Readonly локальная переменная не может быть использована в качестве целевого назначения для док и MEM.

Редактировать: здесь только я добавляю содержимое в pdf документ в другом методе. поэтому мне нужно передать тот же объект doc, не так ли? так почему я не могу использовать ref или вне param.

Технически using не соответствует цели ref.

Пытался посмотреть на MSDN:

A ReadOnly property has been found in a context that assigns a value to it. 
Only writable variables, properties, and array elements can have values assigned 
to them during execution. 

Как объекты становится только для чтения при вызове Методы? В пределах объекта объекта жив, и вы можете делать все, что хотите.

+0

Пожалуйста, покажите короткую, но * полную * программу, демонстрирующую проблему. –

+0

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

+0

Попробуйте скопировать и вставить это в новый текстовый файл и скомпилировать его. Что такое класс «Документ»? Что такое класс PdfWriter? 'Paragraph'? 'Chunk'? 'Phrase'? Я очень сомневаюсь, что они не имеют отношения к этому вопросу и что вам просто нужна * некоторая реализация '' IDisposable'', поэтому используйте ее внутри BCL и добавьте соответствующую директиву 'using'. –

ответ

12

Это потому, что вы объявляете doc и mem ключевыми словами using. Использование MSDN:

Внутри используемого блока объект доступен только для чтения и не может быть изменен или переназначен.

Следовательно, вы получаете сообщение об ошибке только для чтения.


Если вы все еще хотите передавать параметры по ссылке, вы можете использовать try ... finally блок вместо using. Как отметил Джон Скит, этот код аналогичен тому, как расширяется using, но с оператором using, он всегда является исходным объектом, который расположен. В приведенном ниже коде, если AddContent изменяет значение doc, это будет более позднее значение, которое используется в вызове Dispose.

var doc = new Document(PageSize.A4, 5f, 5f, 5f, 5f); 
try 
{ 
    var mem = new MemoryStream(); 
    try 
    { 
     PdfWriter wri = PdfWriter.GetInstance(doc, output); 
     doc.Open(); 
     AddContent(ref doc,ref wri); 
     doc.Close(); 
    } 
    finally 
    { 
     if (mem != null) 
      ((IDisposable)mem).Dispose(); 
    } 
} 
finally 
{ 
    if (doc != null) 
     ((IDisposable)doc).Dispose(); 
} 
return output.ToArray(); 
+0

+1 за помощь и объяснение мне, но это не решает мою проблему. – joshua

+0

См. Мое редактирование для решения этой проблемы. – Szymon

+1

Этот * не * тот же код, что и с 'using' - потому что с помощью' using', это всегда * исходный * объект, который расположен. В вашем «эквивалентном» коде, если 'AddContent' изменяет значение' doc', это будет более позднее значение, которое используется в вызове 'Dispose'. –

6

mem переменная только для чтения, из-за ключевого слова using. Как компилятор должен знать иначе, что он должен распоряжаться при выходе из области использования, когда вы переопределяете его ссылку на переменную.

Но почему вы все равно должны использовать ключевое слово ref? По-моему, вам не нужна ссылка.

+0

может быть здесь не нужен. берут требование генерации документа 'pdf', вам нужно сохранить тот же объект документа. это то, что я сделал. – joshua

+0

Теоретически, контракт вокруг 'using' может просто« располагать все, что находится в переменной в конце блока », поэтому, если вы его отключите, он просто уничтожит все, что вы его переключите, но это не так:) +1 для «вам не нужна ссылка». – Rawling

+0

@joshua: Вы * действительно * должны убедиться, что вы понимаете, что делает 'ref'. Для правильного использования C# важно. См. Ссылку, содержащуюся в комментариях к вопросу. Я уверен, что удаление 'ref' является лучшим решением * здесь. –

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