2016-12-16 4 views
0

Я работаю с сторонним объектом, который реализует IDisposable. Для того, чтобы сделать модульный тест «способным», я создаю обертку. Я понимаю, что объект реализует IDisposable, которому моя оболочка также нуждается в реализации IDisposable.Реализация и использование IDisposable

public interface IWrapper : IDisposable 
{ 
    void Complete(); 
} 

public class Wrapper : IWrapper 
{ 
    private readonly ThirdPartyLib lib; 

    public Wrapper() 
    { 
     lib = new ThirdPartyLib(); 
    } 

    public void Complete() 
    { 
     lib.Comlete(); 
    } 

    public void Dispose() 
    { 
     lib.Dispose(); 
    } 
} 

public class Processor : IProcessor 
{ 
    private readonly IWrapper wrapper; 
    public Processor(IWrapper wrapper) 
    { 
     this.wrapper = wrapper; 
    } 

    public void Process() 
    { 
     // do some work 
     using (wrapper) { 
      // do more work 
     } 
    } 
} 

Пусть процессор впрыскивается в некотором классе, который использует его и процесс() выполняется

  • Что happends в обертку, если мы называем процесс() еще раз? - не будет ли ThirdPartyLib() выдавать исключение, поскольку он был создан только один раз (в конструкторе оберток), и теперь он был удален
  • Не может ли он быть удален до тех пор, пока есть ссылка на него?
  • Если обертка возможно будет построить таким образом, чтобы новый() «ИНГ» из ThirdPartyLib быть выполнена не в конструкторе, но в отдельном методе, скажем, Begin() - например, так:
public class Wrapper : IWrapper 
    { 
     private ThirdPartyLib lib; 

     public void Begin() 
     { 
      lib = new ThirdPartyLib(); 
     } 

     public void Complete() 
     { 
      lib.Comlete(); 
     } 

     public void Dispose() 
     { 
      lib.Dispose(); 
     } 
    } 

Затем, используя его:

using (wrapper.Begin()) { 
+1

Я чувствую, что у нас нет большой картины для этого.Почему «Процессор» обрабатывает только один «Wrapper», который был введен в конструктор? Обычно я ожидаю, что вы «Процессор» будет иметь вызов метода, такой как «Process (обертка IWrapper)», позволяющий обрабатывать эту оболочку, но опять же я был бы в лагере, чтобы вызывающие вызывали вызов «Dispose» на «IWrapper», так как он действительно владеет им. Если это не так, я, скорее всего, реализую 'IDisposable' на' IProcessor' и только распоряжаюсь 'IWrapper', когда это удастся. –

+0

Будет ли реализация IDisposable на IProcessor удалять только Wrapper при размещении IProcessor (в текущем проекте), а не при ударе "}" использования инструкции? Является ли это потому, что (родительский) IProcessor содержит ссылку на IWrapper - даже если мы сказали, что он расположен на "}" – BobSwanson

+0

Вот почему объекты, инициализированные с DI, должны предполагать, что у них есть введенный объект_. Большую часть времени они являются одиночными играми, используемыми другими объектами или, по крайней мере, чем-то другим, управляют временем жизни. Объекты, зависящие от DI, должны просто _use_ объекта и предполагать, что. Независимо от того, что создал входящий объект, он также несет ответственность за его последующее использование. DI похож на «эй, я просто хочу объект, кто-то другой может его создать и удалить» _ – MickyD

ответ

2

Вы правы для беспокойства. Вызов Process() дважды, скорее всего, вызовет исключение. Не вызывать Process() вообще не оставил бы объект нераскрытым.

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

Если Processor ссылается на внешнюю принадлежность Wrapper, тогда он не должен располагать эту обертку вообще.

Если Processor принимает на себя ответственность за Wrapper во время строительства, то он должен распоряжаться этой оберткой в ​​распоряжение временем. Это означает, что Processor должен реализовать также IDisposable.

Если Processor может быть изменен для создания нового Wrapper по запросу, то эта обертка может быть удалена, если с ней выполнено Process().

Или, как вы предположили, если Wrapper может быть изменен для создания ThirdPartyLib по запросу, это тоже может сработать. Но будьте осторожны: позвоните wrapper.Begin(); wrapper.Begin();, оставив один ThirdPartyLib нераскрытым и не связанным. Вам нужно будет немного перестроить ваш API, чтобы это не стало проблемой, и, фактически, это означало бы превращение вашего Wrapper в ThirdPartyLibFactory.

+0

не могли бы вы объяснить, как вызывать: wrapper.Begin(); wrapper.Begin(); оставит один нераскрытый? – BobSwanson

+0

@BobSwanson 'wrapper.Begin()' создает стороннюю библиотеку lib, назовем ее A. Затем вы вызываете ее снова, теперь у вас есть вторая созданная сторонняя lib, давайте назовем ее B. Теперь ваша личная переменная 'lib' указывает на B, и ничего больше не указывает на A. Когда вы вызываете 'wrapper.End()', он вызывает 'lib.Dispose()', который предоставляет B, но A все еще существует и больше не может быть удален, поскольку вы потеряли единственную ссылку на него. – Quantic

1

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

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

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