Обновить
8
0
Толмачёв Дмитрий@FiresShadow

Разработчик ПО

Отправить сообщение
Зависимость сама может не быть IDisposable, в отличие от ее собственных зависимостей, зависимостей ее зависимостей и т.д.
То есть объект косвенно владеет ресурсами (пусть и через свои зависимости), но его класс не реализует IDisposable? Зачем так сделано? Имхо, класс, управляющий управляемыми ресурсами, сам становится управляемым ресурсом (потому что его надо явно освободить), поэтому ему следует реализовывать IDisposable.
Не вижу никаких препятствий, мешающих ViewModel реализовать IDisposable

    class ViewModel : IDisposable
    {
        public Action<ViewModel> DisposeStrategy;
        
        public void Dispose()
        {
            /*тут освобождение своих ресурсов*/

            try
            {
                if (DisposeStrategy != null)
                    DisposeStrategy(this);
            }
            finally
            {
                DisposeStrategy = null;
            }
        }
    }


var viewModel = new ViewModel() {DisposeStrategy = vm => observableCollection.Remove(vm)};
observableCollection.Add(viewModel);
В случае, когда логика освобождения ресурсов может различаться в разных ситуациях, я предложил использовать стратегию. Нужно освободить разделяемый ресурс — освобождаем, не нужно — не освобождаем. Лучше увидеть внутри Dispose применение стратегии, чем увидеть внутри Dispose часть логики освобождения ресурсов (как предлагает автор статьи), а потом разбираться, почему освобождение ресурсов работает совсем не так, как описано в Dispose, и как оно работает на самом деле.

лучше вбрасывать фабрику и использовать ее
Не совсем понял, что вы предлагаете. Какую фабрику? Что она создаёт? Как инициализирует то, что создаёт?
var disposableViewModel = new ViewModel().ToDisposable(vm => 
        {
            observableCollection.Add(vm);
            return () => observableCollection.Remove(vm);
        });
Тут можно было просто добавить событие\делегат в ViewModel, тогда cohesion было бы выше при том же coupling.
Не совсем понял мотивацию для использования.

При использовании Dependency Injection объект класса не только не должен отвечать за жизненный цикл своих зависимостей, он просто физически не может это делать: зависимость может реализовать IDisposable, а может не реализовать, но при этом у нее могут быть свои зависимости и так далее.
У класса есть ссылка на зависимость, по этой ссылке можно вызвать Dispose.

class Foo : IDisposable
{
    IDependency _dependency;

    public Foo(IDependency dependency)
    {
        _dependency = dependency;
    }

    public void Dispose()
    {
        if (_dependency is IDisposable)
            ((IDisposable)_dependency).Dispose();
    }
}


Зависимостями зависимости может управлять сама зависимость. Логику освобождения ресурсов можно поместить в Dispose конкретного класса. Если логика освобождения ресурсов может различаться в разных ситуациях, можно использовать стратегию + фабрику.

В вашем примере логика освобождения ресурсов размазывается по нескольким классам. Часть логики в методе ToDisposable() одного класса (
return value.ToDisposable(Disposable.Empty);return value.ToDisposable(value);), часть логики — непосредственно в Dispose конкретного класса (к которому принадлежит value). Для чего это и в чём выигрыш?
Воу, как карма у меня сразу упала :)
Вот цитата из той статьи:
Если вы назвали фиксированную цену и даже написали детальное техзадание, вам придется на каждом шагу бороться с ним, доказывая, что вот этого в задании не было! С почасовой оплатой вы можете сказать «ок, давайте я оценю, во сколько это вам обойдется» — а там пусть клиент сам решает, стоит ли оно того.
По какой методологии, по вашему мнению, работает автор? Вы можете назвать хотя бы одно место в статье, которое применимо к отношениям между заказчиком и исполнителем-одиночкой и неприменимы к отношениям с небольшой командой разработчиков?

Но суть не в этом. Люди потратили время, написали статью, а вы жалуетесь, мол это мне неинтересно, лучше бы написали на тему, как убедить заказчика, что гибкая методология лучше Fixed Price. Ну неинтересно — закройте статью и занимайтесь своими делами дальше. Никому неинтересно, что вам неинтересно. Ладно, вам дали ссылку на тот материал, о котором вы просили. Вместо благодарности опять жалобы: дескать, мне это неинтересно, я хотел (но никому об этом не сказал) почитать про взаимодействие заказчика и большой команды разработчиков. И такое сплошь и рядом на хабре. В ваших же интересах признать, что мир не вращается вокруг вас и что лучше самому заниматься исполнением своих желаний, а не канючить у окружающих, тем более что в данном случае нужно всего-то набрать пару слов в поисковике. Хотя, конечно, это ваша жизнь, живите как хотите. Это был просто добрый совет от случайного прохожего.
Мы живём в эру интернета, вы могли бы самостоятельно нагуглить интересующий вас материал
«Интуитивные разработчики» все равно написали бы по-своему, они же документацию не читают по определению.
Интуитивные ожидания формируются не случайным образом, а на основании поведения конкретного класса. Я думал, что довольно подробно описал этот процесс, даже два примера привёл. Мне кажется, вы меня регулярно троллите. В прошлой статье вы меня 5 раз спросили про утечки памяти и слабые события, и я вам 5 раз ответил: [1], [2], [3], [4], [5]. В этой статье всё с ног на голову пытаетесь перевернуть.

Ладно, если по существу, чтобы не было бы разрыва между интуитивными ожиданиями и документацией, нужно было или в классы, реализующие интерфейс, добавить методы AddRange, RemoveRange, или, повторюсь, в документации написать, что можно добавлять только по одному элементу.
Это не имеет значения — важен результат.

А если причина не важна, то как, спрашивается, учиться на чужих ошибках? Как не совершать подобных ошибок в будущем? Одна из целей моей статьи — предостеречь читателей от подобных ошибок. Если для вас всё это не имеет значения — ну что же, ваше право, можете дальше игнорировать интуитивные ожидания разработчиков, это останется на вашей совести.
Вообще, мой вопрос был, почему вы говорите, что «все проблемы связаны отнюдь не с неким «реальным контрактом»», а в ответ я услышал лишь кучу эмоций по поводу нарушения обратной совместимости и оценок компетентности разработчиков WPF. Вы, несомненно, имеете полное право на эмоции, и спасибо что ими поделились, но обсуждение темы по существу было бы гораздо приятнее и полезнее.
Приведённый в статье совет про выбор из двух контрактов актуален вне зависимости от того, является ли один контракт интуитивными ожиданиями, или же оба контракта являются формальными. Повторюсь, в случае, если вы реализуете наследника, опирайтесь на наиболее конкретный и специфичный контракт среди двух.
Формальный контракт в .NET Framework 4 говорит, что Add означает «One or more items were added to the collection.». Формальный контракт в .NET Framework 4.5 для Add — «An item was added to the collection.».
Сделав так, как вы говорите, вы нарушите публичный формальный контракт из версии 4.5.
Нарушение контракта, являющегося интуитивными ожиданиями — тема тонкая и холиварная, но вот нарушение формального контракта — бесспорный факт. Рекомендую при наследовании использовать контракт с наибольшими ограничениями — т.е. добавление единственного элемента, а при использовании — с наименьшими ограничениями, т.е. добавление нескольких элементов.
Немного поясню. В .NET Framework 4 сказано, что Add означает, что один или несколько элементов добавлены в коллекцию, а разработчики, судя по всему, руководствовались интуитивными ожиданиями, сформированными ObservableCollection, что Add означает добавление одного элемента. А если бы в документации было сказано, что Add означает добавление одного элемента, то никто бы не пытался реализовывать коллекции таким образом, что Add означает добавление нескольких элементов, и не сталкивался бы с проблемами. Ещё было бы неплохо в документации указать, что Reset означает очистку коллекции и добавить элемент, сигнализирующий о произвольном изменении коллекции. Совпадение интуитивных ожиданий и формальных требований уменьшает вероятность ошибки. В данном же случае, судя по всему, формальная документация писалась для абстрактного интерфейса, а интуитивные ожидания формировались на основании конкретного класса.
обрушил производительность (-1)
зато легализовал творчество разработчиков, неспособных прочесть спецификацию (+100500)

Согласен, я как раз писал, что
Так что я считаю, что изменение документации решило одну проблему, но одновременно создало другую (для решения которой нужно добавить ещё один элемент в перечисление)


И все проблемы связаны отнюдь не с неким «реальным контрактом», а с застарелыми багами в реализации.

В любой непонятной ситуации проще всего не раздумывая обвинить во всём конечных исполнителей. Однако давайте подумаем, а почему конечные исполнители реализовали «кривые контролы из поставки WPF» именно так? Может быть они были обиженными на весь мир садистами, намеренно допустившими ошибку? Звучит бредово. А может быть их интуитивные ожидания о поведении ObservableCollection отличались от того, что написано в msdn? Звучит правдоподобно. Итак, есть проблема — интуитивные ожидания большинства разработчиков не совпадают с описанием в документации. Какие тут могут быть решения? Ну, проще всего не раздумывая возложить ответственность за решение проблемы на конечных исполнителей. Мол, ребята, вызубрите наизусть весь msdn и регулярно его повторяйте. Поможет это избавиться от багов? Я думаю, не поможет. Вариант второй — сделать так, чтобы интуитивные ожидания большинства программистов совпадали с описанием в документации. Именно так я оцениваю случай с изменениями в документации. Если есть конструктивная критика — я буду рад услышать чужое мнение. Фраза же «всё сказанное чепуха, во всём виноваты конечные исполнители, наделавшие багов» не очень похожа на конструктивную критику, потому что не раскрыта мысль, а почему именно чепуха, почему «все проблемы связаны отнюдь не с неким «реальным контрактом»».
Add и Remove точно так же могут сигнализировать о множественном изменении.

Работая с ObserverableCollection, вы на практике хотя бы раз сталкивались с таким случаем? Можете пожалуйста привести пример?
У ObserverableCollection нет метода AddRange. Каждый раз при вызове метода Add (который принимает в качестве параметра ровно один элемент) срабатывает событие, у которого в NewItems находится всегда ровно один элемент. Так что для NotifyCollectionChangedAction.Add то что написано в msdn истинно и на практике.
IBM — молодцы!
У нас есть роботы, делающие автомобили.
У нас есть роботы, делающие роботов.
У нас (почти) есть роботы, двигающие науку.
Ключевое слово probably. Забавный мем.
Конечно, типовая ObservableCollection делает Reset только при Clear, только любой шаг вправо или влево сделает ваш код неработоспособным.

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

Информация

В рейтинге
Не участвует
Откуда
Россия
Дата рождения
Зарегистрирован
Активность