All streams
Search
Write a publication
Pull to refresh
11
0

User

Send message
Э нет. Семантика IDisposable — я с ресурсом закончил, освободи его немедленно.
Я бы сделал так, что если мы стрим передали снаружи — его не закрывать. Если создали внутри то закрывать. А иначе, поведение не очевидное.
Скажем честно, этот параметр — плохая архитектура.
Если эта зависимость не диспозабл, а внутри нее какие-то диспозабл зависимости, то этот код должен переехать глубже (к диспозабл зависимостям).
Я понимаю что такое Owned из Autofac, и его использование, что характерно, оверхеда почти не добавляет (потому что весь оверхед в том, что в фабрику мне нужно добавить слово Owned). При этом я делегирую управление зависимостью Autofac. Но я продолжаю не понимать зачем мне ваша реализация без DI контейнера? Какой от нее профит?
Вы в этой статье написали некую реализацию
IDisposable<T>
которая является оберткой вокруг IDisposable. При этом совершенно не очевидно, как она решает проблемы вынесенные в начало статьи, а главное, не понятно зачем эти проблемы решать и проблемы ли это. Именно это я называю «обертки ничего не упрощают, при этом усложняя код или компиляцию».
Нельзя сделать так.
IDependency не обязан наследоваться от IDisposable
Экземпляр реализации IDependency может переиспользоваться (пример — соединения)
У реализации IDependency могут быть собственные зависимости


Если бы вы не вырывали из контекста, вы бы увидели, что пример кода там был в случае, если хочется больше контроля над disposable зависимостями. А значит данная конкретная зависимость наследуется от IDisposable. Наиболее правильно (и об этом я пишу выше), передать управление зависимостями DI контейнеру.
Например, класс использует эти ресурсы но не управляет ими.
Как тот же StreamWriter поверх переданного снаружи стрима. Смысл в том, что если ваш класс не создает внутри себя зависимость, а получает ее снаружи, он не должен ее и освобождать, потому что ему не известно что с этой зависимостью предполагается делать дальше.
Лучше увидеть внутри Dispose применение стратегии, чем увидеть внутри Dispose часть логики освобождения ресурсов (как предлагает автор статьи), а потом разбираться, почему освобождение ресурсов работает совсем не так, как описано в Dispose, и как оно работает на самом деле.

Автор вообще пишет пургу на тему диспозабл. Предлогаемые им обертки ничего не упрощают, при этом усложняя код или компиляцию.

Наиболее правильно в случае использования DI контейнера переложить управление временем жизни зависимости на него (и задать явно при инициализации как этим временем жизни надо управлять). Если же вы хотите больше контроля за освбождением диспозабл зависимости, то имеет смысл вбрасывать не зависимость а фабрику от нее и использовать конструкцию using.

Не совсем понял, что вы предлагаете. Какую фабрику? Что она создаёт? Как инициализирует то, что создаёт?


Если вы работаете с DI контейнером, можно сделать так:

class Foo : IDisposable
{
    Func<IDependency> _dependencyFactory;

    public Foo(Func<IDependency> dependencyFactory)
    {
        _dependencyFactory= dependencyFactory;
    }

    public void SomMethod()
    {
          ...
         using(var dependency = _dependencyFactory())
         {
              ///используем зависимость.
         }
    }
}

Не стоит делать как вы предлагаете. В этом случае следующий потребитель вашей зависимости может получить disposed зависимость.
Если вы хотите сами контролировать время жизни, лучше вбрасывать фабрику и использовать ее внутри конструкции using
string stroka = toString(funkciya)


И что же этот вызов должен вернуть?
Не, ты не прав. «Для всех X, принадлежащих такому-то множеству, выполняется такой-то предикат» — это утверждение (теоремы, леммы и т.п.).
А в доказательстве используется «Пусть x — любое значение из множества… тогда...» или «Возьмем x — любое значение из множества… тогда...»
И это, в принципе, присвоение. Мы после этого проводим логическую цепочку основываясь на том что значение из множества…
Менял с Unity на Autofac. В Autofac лучше управление временем жизни зависимостей, а это оказалось важно.
А я в паре проектов менял DI контейнер.
Я, если мне нужна конкретная семантика завожу специальный тип, а вот используя Func никакой дополнительной семантики не влкадываю.
Func<TВася> и Func<TПетя> имеют одинаковую семантику. Оба они возвращают объект типа, соответствующего генерик параметру. Ничего сверх того они не обещают.
Так Func и есть наименование типа, которое ясно и четко говорит что это фабрика (семантически).
В вашей трактовке помимо Func надо смотреть еще и на тип-параметр, что усложняет и реализацию, и использование.
Вдобавок это противоречит самому понятию generic, так как ваш Func имеет разную семантику для разных типов-параметров.

Простите, но Func это семантически не фабрика, а функтор. И не надо в него вкладывать семантику, которой в нем нет.
Генерик параметр в нем говорит что этот функтор возвращает объект такого типа. Больше он ничего семантически не гарантирует.
Без такой семантики Func просто не нужен по построению.


Чего это не нужен? В этом случае мы перекладываем ответственность по управлению инстансами нашего сервиса на эту фабрику. И явно говорим, что нам все равно какой экземпляр нам будет возвращен каждый раз когда мы вызовем фабрику.
То есть мы не привязываем наш класс потребитель к конкретному экземпляру который вбросили в конструктор, а получаем в каждом месте вызова фабрики тот экземпляр, который DI контейнер посчитает нужным нам отдать. А DI кнтейнер пусть управляет временем жизни этого экземпляра так как он настроен.

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


А это определяется семантикой которую в себе несет объект. Если он (его название) содержит в себе семантику контекста — он должен сохранять внешнее состояние до смены контекста. Если у него в семантике заложен Cache, соответственно должен вести себя как кеш и т.п.
Семантика у вас не в фабрике, а в типе получаемого из фабрики объекта. То есть наименование типа объекта должно говорить что это
— сервис и тогда нам не важно что внутри его состояния и мы его состояние снаружи менять не должны;
— контекст и тогда мы можем менять его состояние и рассчитывать, что его состояние сохранится пока контекст не переключится
— объект данных и тогда мы вправе рассчитывать на все время новый проинициализированный объект.
Между прочим, у 1С есть модуль учета имущества.
Вот это вот
если Func — можно повторно дергать для получения новой реализации
непонятно откуда взялось. На основании чего вы вкладываете в делегат семантику отдачи каждый раз нового объекта мне не понятно.
Нет. Func не закладывает такой семантики. Равно как и Lazy не закладывает семантики singleton, на самом деле. Просто класс потребитель сервиса не должен ожидать от поставщика этого сервиса никакого поведения, отличного от описанного контрактом (интерфейсом). То есть он не должен вообще думать о внутреннем состоянии сервиса, который ему сгенерировала фабрика. Все о чем он должен думать — это что сервис выполняет обещанные контрактом операции.

Information

Rating
Does not participate
Registered
Activity