Хранение ссылки на объект, созданный в инициализаторе конструктора - PullRequest
4 голосов
/ 06 октября 2011

Сводка : если я создаю объект в инициализаторе конструктора, как мне сохранить ссылку на него, чтобы я мог ссылаться на него позже?

Подробнее :

У меня есть класс (LibBase, ниже), который требует StreamWriter в качестве параметра построения. У меня нет исходного кода для LibBase - он находится в сторонней библиотеке.

public class LibBase
{
    public LibBase(System.IO.StreamWriter wtr) { ... }
}

Я получил MyClass из LibBase, и в конструкторе MyClass я хочу передать экземпляр MyWriter (производная форма StreamWriter) в базовый класс. Я делаю это следующим образом.

public class MyWriter : System.IO.StreamWriter
{
    public MyWriter(int n) { ... }
    // Contains unmanaged resources
}

public class MyClass : LibBase
{
    public MyClass(int n)
    : LibBase(new MyWriter(n))
    { }
}

Проблема в том, что MyWriter требует удаления, поэтому MyClass должен утилизировать его (и реализовать для этого IDisposable) , но MyClass не имеет ссылки на созданный экземпляр MyWriter так что я не могу избавиться от него . Синтаксис инициализатора конструктора, похоже, не позволяет my сохранять ссылку.

Мое решение - перекодировать MyClass следующим образом:

public class MyClass : LibBase, IDisposable
{
    public MyClass(Encoding enc)
    : this(new MyWriter(enc))
    { }

    private MyClass(MyWriter wtr)
    : LibBase(wtr)
    { this.wtr = wtr; }  // store reference

    private MyWriter wtr;

    // (implement IDisposable using wtr member variable
}

Закрытый конструктор хранит ссылку на экземпляр MyWriter, поэтому я могу его утилизировать позже.

Мои вопросы :

  1. Что мне здесь не хватает? Я чувствую, что я борюсь с языком. C # обеспечивает лучший способ сделать это?
  2. Если язык не поддерживает это напрямую, есть ли лучшее решение, чем мой метод частного конструктора?
  3. Есть ли какие-либо комментарии по поводу дефектов в моем решении?

Ответы [ 3 ]

5 голосов
/ 06 октября 2011

Я не думаю, что вы ничего здесь упускаете.Ваше решение выглядит нормально для меня , если LibBase действительно не позволяет вам получить доступ к автору, которого вы передали конструктору.

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

На канал Эрик Липперт :

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

Полагаю, это то, что невстретить бар, даже если это было сочтено желательным в первую очередь.(Существует постоянная стоимость, превышающая затраты для команды C # - это ментальная стоимость каждой функции, поглощаемой разработчиками C #, и постоянная стоимость, которую каждая новая функция потенциально затрудняет для добавления функции next .)

2 голосов
/ 06 октября 2011

Ваше решение кажется нормальным ... Не думаю, что вы что-то упускаете ...

Если вы хотите изменить реализацию (по любой причине):

  • Вы можете реализовать это, не наследуя от LibBase, но имея экземпляр в качестве частного члена ...
  • другим вариантом было бы реализовать шаблон Factory для MyClass, таким образом, не имея общедоступного конструктора и создавая экземпляр фабрики StreamWriter и т. Д.

НО, как я сказал, в вашем решении нет ничего плохого (если это случается часто, вам, вероятно, следует переосмыслить свой дизайн).

РЕДАКТИРОВАТЬ - согласно комментарию:

То, что я имею в виду под «созданием на стороне фабрики StreamWriter», заключается в следующем: создайте Фабрику для MyClass, чтобы каждый, кому нужен экземпляр, использовал Фабрику ... там вы можете создать экземпляр StreamWriter в методе Фабрика и передать это как параметр к MyClass ... таким образом, вы могли бы даже реализовать некоторые причудливые вещи, такие как "какой экземпляр MyClass использует данный экземпляр StreamWriter?" или какой-то кеш для MyClass / StreamWriter экземпляров и т. д.

1 голос
/ 06 октября 2011

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

Любой, кто имеет дело с MyClass, должен обработать удаление, но код, написанный для использования LibBase, не делает этого, поэтому вы не можете простобросить экземпляр MyClass в код, написанный для обработки LibBase.В таких случаях наследование не очень уместно.Конечно, если LibBase удваивается как интерфейс, вы не можете помочь, в этом случае ваш обходной путь кажется лучшим, что вы можете сделать.

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