C# необнуляемое поле: Lateinit? - PullRequest
0 голосов
/ 23 марта 2020

Мне интересно, как использовать поля класса с поздней инициализацией в C# с обнуляемыми ссылочными типами . Представьте себе следующий класс:

public class PdfCreator { 

   private PdfDoc doc;

   public void Create(FileInfo outputFile) {
       doc = new PdfWriter(outputFile);
       Start();
   }

   public void Create(MemoryStream stream) {
       doc = new PdfWriter(stream);
       Start();
   }

   private void Start() {
      Method1();
      // ...
      MethodN();
   }

   private void Method1() {
      // Work with doc
   }

   // ...

   private void MethodN() {
      // Work with doc
   }
}

Приведенный выше код очень упрощен. Мой реальный класс использует еще много полей, таких как doc, а также имеет несколько конструкторов с некоторыми аргументами.

Используя приведенный выше код, я получаю предупреждение компилятора о том, что doc не инициализирован, что правильный. Я мог бы решить эту проблему, установив тип doc на PdfDoc?, но тогда я должен использовать ?. или !. везде, где он используется, что неприятно.

Я также мог бы передать doc как параметр для каждого метода, но помните, что у меня есть такие поля, и это нарушает принцип чистого кода в моих глазах.

Я ищу способ сообщить компилятору, что я буду инициализировать doc перед его использованием (на самом деле я делаю это, у вызывающей стороны нет возможности получить исключение нулевой ссылки!). Я думаю, что Kotlin имеет модификатор lateinit именно для этой цели.

Как бы вы решили эту проблему в "чистом" C# коде?

Ответы [ 3 ]

0 голосов
/ 23 марта 2020

Поздняя инициализация может быть непростой задачей с ссылочными типами, допускающими обнуляемость

Один из вариантов - сделать переменную-член обнуляемой и добавить функцию для переноса доступа:

private PdfDocument? pdfDocument = null;

private PdfDocument? GetDocument()
{
  if(pdfDocument == null) throw new InvalidOperationException("not initialized");

  return pdfDocument;
}

С этим можно Теперь вы можете изменить ваши методы следующим образом:

private void Method1() 
{
  var doc = GetDocument();

  // doc is never null
}

Теперь ваш код более точно моделирует намерение. pdfDocument может быть null, даже если ненадолго, и ваши методы могут получить доступ к документу, зная, что они никогда не вернутся null.

0 голосов
/ 23 марта 2020

ваш код выглядит как шаблон, Подробнее об этом

    public class PdfBuilder
    {
        private PdfDoc _doc;

        private PdfBuilder(PdfDoc doc)
        {
            _doc = doc;
        }

        public static PdfBuilder Builder(FileInfo outputFile)
        {
            var writer = new PdfWriter(outputFile);
            return new PdfBuilder(writer.ReadPdfDoc());
        }

        private void Build() 
        {
            Stage1();
            StageN();
        }

        private void Stage1() 
        {
            // Work with doc
        }

        // ...

        private void StageN() 
        {
            // Work with doc
        }
    }
0 голосов
/ 23 марта 2020

Лучшее решение, которое я нашел до сих пор, это:

private PdfDoc doc = null!;

Это удаляет все предупреждения компилятора. Может быть, это C# версия Kotlin 'lateinit'? Я не смог найти никакой документации для этой "функции".

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...