« first day (892 days earlier)      last day (2139 days later) » 

4:03 AM
@VladD Давайте начнем с начала.
Есть что угодно, которая обладает свойством Items, методом Add и событием ItemAdded. Этакий ItemsHolder. Если мы сделаем этот ItemsHolder : IList, то получим вообще "List".

Просто для обычных коллекций нормально использовать в пределах класса клиента и делать lock(listObj), а вышеопианные вещи они шарятся по всему приложению (но по факту обладают всеми признаками коллекции, хоть вообще IList)
Это списки чего-угодно, пулы, очереди задач и вообще вещь частая. Можно даже представить его как "список который расшаривается".
lock(lockState) вещь прямая и рабочая если просто не забывать его использовать.
Вычитывание всей коллекции на ItemAdded как-то ну вообще не то. Планировщик на клиенте (тот же UI-поток) будет эффективнее)

Ваше STA я понимаю так: вместо itemsHolder.Items сделать itemsHolder.WithItems(Action<T> list) и уже ItemsHolder внутри себя застаить подождать выполнение Add и ItemAdded планируя выполнение. Так?
И если я верно понял, то это все равно не решает проблемы подписки:
- vm подписалась на ItemAdded
 
 
10 hours later…
2:27 PM
@vitidev Ну если начинать совсем сначала, то я бы не делал коллекцию, которая может отправлять события из одного потока. Это опасная вещь. У меня такого в софте нигде нету, а всегда есть ровно один поток, из которого отправляются события.
И у меня не бывает IList<T>, который защищён мьютексом и доступен любому потоку.
Если это частая вещь, то у кого-то должен быть опыт работы с ними. Но у меня его нету. Хуже того, я вижу серьёзные проблемы с таким подходом.
Например, пусть поток P1 добавляет элемент A, и сразу же после этого поток P1 удаляет элемент A. Тогда наблюдающая VM получает события в разных потоках. Само собой разумеется, на время маршаллирования в другой поток мы не можем блокировать коллекцию, а значит, события приходят в VM-поток асинхронно. Поэтому в зависимости от планировщика потоков событие удаления может прийти раньше события добавления.
Что делать в этой ситуации VM?
 
2:46 PM
Ох, следует вместо "и сразу же после этого поток P1 удаляет элемент A" читать "и сразу же после этого поток P2 удаляет элемент A"
 
 
1 hour later…
3:58 PM
@VladD Я честно говоря вообще не понимаю где вы видите проблему с потоками и вызовами событий. Можно спокойно иметь **внутренний лок** в списке и не давать добавлять новый элемент, пока предыдущий не добавлен и все не были уведомлены. Ну или планировать добавление внутри коллекции в один поток чтобы было. События не будут переставлены. Да они будут из разных потоков (но не перставлены) или из одного - это неважно для VM которой все равно нужно будет прыгать в UI поток.

Проблема в том, что нужно подписаться на события и забрать уже имеющееся и потом долго отрисовать и за это время не потеря
 
@vitidev А как вы собираетесь ликвидировать описанный сценарий?
 
перестановку событий? а их нет же. внутренний лок достаточен
 
@vitidev Эээ...
Я описал сценарий, когда они есть.
И я не вижу, чем внутренний лок поможет.
Вы ведь не собираетесь делать кросс-поточный вызов под локом?
Ну или приведите примерный код. По идее нужно лишь добавление одного элемента и его удаление.
 
собираюсь. кто то скажет что это плохо ибо подписчик может долго обрабатывать событие но тут уже спорное дело. я считаю что это вам не просто список, а целая транзакция "добавлено - все уведомлены - система в новом состоянии"
 
@vitidev А, тогда я соскакиваю. Вызов в другой поток под локом -- это приглашение к проблемам.
 
4:03 PM
хотя в асинке лучше запланировать конечно а не локи
планировщик внутри коллекции устроит?
 
@vitidev Я не совсем понимаю, что это. Можно пример кода?
 
ну вот как Dispatcher.BeginInvoke
 
@vitidev Не, давайте вы покажете код. Потому что от того, что внутри BeginInvoke, а что снаружи, зависит корректность тех или иных вещей.
По моему опыту, многопоточность -- это не та область, где можно примерно прикидывать, а надо очень точно.
 
ну это же простая идея. кто то вызвал из любого своего потока list.Add. внутри этого Add не началось сразу добавление, а запланирвоалась операция в ассоциированном шедулере потока и сразу же вернулось awaitable вызывателю чтобы он ждал. Далее внуренний шедулер просто выполнит действие в одном потоке. Таким образом работа внутри будет всегда в одном потоке. События можно планировать в том же шедулере если хочется быстрее отпустить awaitable
 
@vitidev Окей, то есть все события отправляются из одного потока? Это намного лучше, да.
Это и есть то, что я подразумевал под STA.
 
4:15 PM
только задачу не решают. Vm забрала список и отпустила коллекцию и собирается в своему УИ потоке рисовать. За это время может спокойно прилететь пара Added которые нужно не потерять.
коллекция и VM не могут быть в одном потоке потому что выдать такой коллекции UI поток непозволительная роскошь.
потому лучший вариант что я придумал - точно так же пусть VM юзает свой шедулер и планирует все в него
правда.... я так все время и делаю то, но никогда об этом не задумывался
 
@vitidev Ну а в чём проблема? Пусть все Added накапливаются, и после отрисовки их можно скопом забрать.
 
получается что я заберу список в UI потоке. а в хендлере события сделаю прыжок в UI поток, ведь надо менять биндинги....и таким образом само собой делается решение 3
 
А если они придут потом, пусть стукнут в главный поток.
@vitidev Не-не, список надо забирать в его потоке
 
выходит что поскольку я все прокидываю в UI поток то проблема решается сама собой. главное ВСЕ сделать в UI потоке (и забирание тоже)
чой та
 
Потому что события к вам приходят в другом потоке, и основаны на содержании в том потоке
Ну представьте себе, что вы прочитали в VM-потоке список { "A" }, а тем временем в потоке списка к вам приходит событие "удалить элемент B"
Наши действия?
Смаршаллировать удаление элемента B в главный поток?
Окей, а у главного потока данные прочитаны в другой момент, и там элемента B нету
 
4:25 PM
удалить элемент B попадет ко мне в VM. я делаю что то типа Dispatcher.BeginInvoke и операция по удалению элемента б из вьюмоделей запланируется в очередь. а тем временм добработает обработка списка А
стоп стоп
до удаления B кто то его добавит. а у нас нет реордера событий - и в том же порядке события добавил - удалил запланируются и в VM. ничего не переставляется
 
Ну вот вы только начинаете читать
Подписались на событие и читаете в главном потоке список
Получаете { "A" }
А тем временем прилетает событие "удалить B"
Т. к. оно могло реально стартовать до того момента, как вы начали читать в VM-потоке
Синхронизацию событий вы обеспечили, да
Но вы не синхронизировали чтение с событиями
 
нет
- уходим в главный поток
- и только теперь подписываемся (с этого момента все изменения планируются после окончания нашей работы)
- забираем список
- рисуем
-отпускаем главный поток
-срабатывают запланированные изменения

есть проблема чтения коллекции - ее нужно будет сделать потокобезопасной, но по прежнему не вносить вызов событий в эти локи
 
@vitidev Что значит "уходим"? В каком смысле "отпускаем"? Какой юзкейс вы описываете? Я не могу читать ваши мысли.
 
юзкейс прежний: мы подписываемся и забрали содержимое списка и нам нужно время на отрисовку полученных данных. За время отрисовки могут появиться новые элементы которые тоже нужно бы добавить в конец списка. Мы получили события но не смогли их обработать сразу ибо данные еще рисуются. А значит мы планируем изменение коллекции после отрисовки
 
@vitidev Мы забрали содержимое списка до подписки или после? В каком потоке?
 
4:35 PM
если мы подпишемся и заберем в потоке коллекции (тут порядок забирания и подписки не имеет значения), то для рисования забранных данных нам нужно будет уйти в UI и пока мы туда уходим 100 раз может прилететь Added. И тут планировищк не поможет. тут только буферы и маркеры

если мы подписываемся забираем в UI потоке, то тут только сначала подписка, а потом забор. И все события Adeed планировать в UI поток. Тут сложность в том, что мы забираем коллекцию из другого потока, а значит нужен lock(innerLIst)
щас я накидаю класс
 
Хорошо, мы подписались в UI-потоке, на этот момент коллекция = { A, B }. Сразу после этого кто-то удаляет B, и событие об удалении приходит в потоке коллекции. Затем мы считываем содержимое коллекции в UI-потоке, получаем { A }. Затем к нам приходит смаршаллированный из потока коллекции ивент "удалить B" в UI-поток. Наши действия?
Не, второй подход мне не нравится. Я за первый подход. Считать в потоке коллекции, подписаться, замаршаллировать текущий состав коллекции и все её последующие изменения в UI-поток.
 
ну тут беда. собственно потому я и затеял весь этот разговор. честностиради я должен сказать что у меня нет удаления а только Add. Так уж устроено что ТОЛЬКО эта VM потом и сможет вызывать Remove (такая архитектура)

но в общем случае проблема конечно будет
VM также особенна тем что в отличие от других вынуждена прыгать в UI поток
в общем случае не знаю.
 
4:59 PM
@vitidev А чем плох первый подход?
Вроде бы он универсален
 
5:10 PM
Порядок прихода в потоке коллекции по идее совпадает с порядком в UI-потокею
 
5:25 PM
По поводу вопроса / ответа
Разве не говорит то, что конструктор родительского класса обращается к полям дочернего о неправильной архитектуре?
 
@Trymount А конструктор и не обращается
 
@VladD первый подход это буферы? так там та же самая проблема с "удалили В". Разве что отдельно обрабатывать удаления при очищении буферов
 
Обращается виртуальный метод
@vitidev Не, не буферы
Смотрите
Вот у нас начальный момент, нужно подписаться.
Мы переходим в поток коллекции, там считываем коллекцию, посылаем её (через BeginInvoke) в UI-поток, подписываемся.
При приходе ItemAdded отправляем новый элемент в UI-поток через BeginInvoke
Всё
 
а как мы будем узнавать поток коллекции?
 
В таком случае кто-то может попытаться в этом виртуальном методе создать экземпляр "себя" и получится бесконечные вызовы (в вашем примере в DoSomething написать Child1 child1 = new Child1();
 
5:31 PM
@Trymount Вот пример. У вас есть такой код class Animal { abstract string GetName(); public Animal() { Logger.Log("Создали " + GetName()); }} Чем плохо?
@Trymount Ну да, но то же случится, если просто в конструкторе создать новый экземпляр себя. В чём отличие?
@vitidev Угу, вот это хороший вопрос. У меня делалось так:
Есть понятие Engine, как бы объект, представляющий STA.
И он реализовывал функцию с семантикой наподобие BeginInvoke (точнее, InvokeAsync)
Мы знаем, в каком Engine живёт коллекция (нарпимер, она сама наследует Engine, или как угодно иначе)
Ну и соответственно можем запустить наш код там
По сути, Engine -- это однопоточный SynchronizationContext, типа WPF-овского
 
@VladD если пишем библиотеку, то дочерний класс не знает нашего кода. И пишет DoSomething как считает нужным (он же не знает, что тот в конструкторе вызывается). Но вообще пример с Animal более менее пояснил, когда такое может случиться. Спасиб)
 
как можно забыть сделать lock(lockstate), так можно и не вызвать через Engine не ожидая что коллекция многопоточная, а каждую вызывать перебор. И никто ведь не подскажет что "тут надо было через Engine@
 
@Trymount В общем случае да, дочерний код не знает, и должен читать документацию. Вообще, наследование намного сложнее, чем мы привыкли считать
@vitidev А это обходится на уровне внешнего интерфейса
Например так:
class StaCollection<T> : Engine
{
    List<T> payload = new List<T>();
    public async Task Add(T t)
    {
        await RedirectToSelf(); // ru.stackoverflow.com/a/458425/10105
        payload.Add(t);
        FireAdded(t);
    }
}
Заодно внутри не нужны блокировки
 
это добавление. а как же мы вычитаем содержимое
 
Здарова всем
 
5:41 PM
@vitidev Точно так же? Сейчас
@Bretbas Даров!
public async IReadOnlyCollection<T> GetSnapshot()
{
    await RedirectToSelf();
    return payload.Clone().AsReadOnly();
}
Clone медленный, конечно
 
хочу видеть содержимое RedirectToSelf
 
8
A: Как правильно уменьшить размер стека?

VladDВы можете, например, воспользоваться конструктором Thread с указанием максимального размера стека. Если вы планируете запускать Task на этом потоке, имеет смысл реализовать TaskScheduler, который перекинет Task в этот поток. Или можно воспользоваться готовым scheduler'ом, например, WPF. Пр...

Там есть RedirectToDispatcher
И RedirectToThreadPool
Аналогично пишется RedirectToSynchronizationContext
 
@VladD оо...у Вас тут беседа:)
 
@Bretbas Ага :) Асинхронность и всё такое
@vitidev Ну и соответственно RedirectToSelf = RedirectToSynchronizationContext(this.context)
 
@VladD Злооо:)
 
5:46 PM
изучу позже. не знал что можно переключить поток иначе чем передачей делегата в какой нибудь пул, синкконтекст или диспатчер
ну и Task.Yield
 
@vitidev Мне очень нравится эта техника. Просто одной строчкой переходим куда надо
Если лень писать свой SynchronizationContext, можно тупа взять Dispatcher
@Bretbas Даааа! Async/await вообще очень жирная фича. Там много всего хорошего.
@vitidev Была знаменитая статья "await anything"
Рекомендую!
 
@VladD я вообще на async/await обиделся. Он мне по каким то причинам диспозил контекст раньше чем я асинхронно сохранялся... день убил на то, чтобы понял что за хрень
 
@Bretbas Ну, зря ты так на него. Async/await -- это лучшее, что есть в многопоточном императивном программировании на сегодняшний день среди всех языков. Не зря его утащили в JS, Python, Scala, и тащат в C++
С ним обязательно надо дружить
А какой контекст он задиспозил?
 
@VladD не, я с ним дружу. Но надо с ним поаккруратнее
@VladD EF контекст
 
@Bretbas Ну эт да, многопоточность всё же самое сложное в программировании
@Bretbas Ааааа! Хм. А разве с EF можно работать из нескольких потоков одновременно? Не знал.
 
5:52 PM
private async void View_FormClosing(object sender, FormClosingEventArgs e)
{
	// Сохраняем данные
	await appContext.SaveChangesAsync();
	appContext.Dispose();
}
@VladD вот на этом методе он непонятный треш вытворял
 
A K
@VladD Можно, EF6 поддерживает
 
@Bretbas Ага, и пока у нас await, приложение и закрылось?
 
типо того что-то:)
 
@AK Круто! Я отстал от жизни.
@Bretbas Тут проблема с async void как бы
Async void -- жди подвоха
Об этом предупреждали проектировщики
То есть пользоваться им приходится
 
A K
@VladD Ну, это просто кто чем пользуется. Вот вы работаете с WPF и WinForms... а я WinFoms уже забыл сколько лет назад видел и вообще UI... одни сплошные службы ОС windows
 
5:55 PM
@VladD ну если это конечный метод то можно
 
Но это по сути fire-and-forget, а не дождаться результата, как в нормальных функциях
@AK Не-не-не, в Winforms меня не затащить ни за какие коврижки
Я о нём только знаю, что ничего не знаю
@AK А вот службы не доводилось
О, можно вопрос?
 
A K
@VladD Да, но только отвечу уже с мобильного )
 
Как из службы показать нотификацию пользователю?
 
A K
@VladD Не знаю, у меня в корпоративном сегменте вообще нет в этом необходимости. Я так понимаю, что это где-то "служба может взаимодействовать с рабочим столом"?
 
@AK Проблема в том, как найти текущего/активного юзера?
Если нет необходимости, то всё хорошо
(Я вообще нежно люблю блог Реймонда Чена)
 
A K
6:00 PM
@VladD А что такое вообще активный user? ))) Если я в терминальной сессии сижу (mstsc), например - и disconnect сделал?
 
@AK Вот-вот! Про это и статья
@Bretbas (но хвост этой статьи только про Windows RT, с WPF такое не сработает)
 
@VladD ой блин, ща вообще не до этого:( Нужно срочно написать приложенице..на winforms....замучался уже:(
 
@Bretbas WinForms? Сочувствую.
 
@VladD Там просто жесть какая то
 
@Bretbas Угу, могу себе представить. Всё вручную?
 
6:12 PM
@VladD Да я уже задолбался с этими DataGridView, DataGridViewRow, DataBindingSource, DataBindingNavigator и тд
 
@Bretbas Угу, я в DataGrid даже в WPF не совался, очень уж он стрёмный
 
@VladD на самом деле я бы и в WPF и в Winforms бы разобрался с табличным представлением данных. Просто суть в том, что эти DataGridView и DataGrid настолько мощные инструменты, что меня просто не хватает на это:)
 
@Bretbas Ну они вот как-то пришли мимо меня (не без моего участия). Наверное да, наверное мощные.
Кстати, я, кажется, понял, почему continuation passing style есть в функциональных языках, и нету в императивных
В функциональных языках continuation текущей функции -- это просто хвост функции от данной точки вниз до конца.
А в императивных языках не так: мы можем быть в середине цикла.
Async/await использует внутри continuation passing style (возврат из await выполняет continuation), и ему приходится для этого сильно переписывать код.
 
@VladD блин, извини...мне нужно делать:(
 
@Bretbas Угу, понимаю
 
6:26 PM
@VladD у меня еще одна проблема. Хочу чтобы при нажатии на закрыть у формы WPF она не закрывалась а дергала vm.Cancel и уж потом vm вызовет свое событие RequestClose или ещекак и уж тогда форма закроется

я в OnClosing делаю e.Cancel=true и пытаюсь вызвать vm.Cancel но он упорно твердит что "во время зарктыия нельзя менять визибилити и так далее"
 
@vitidev Угу, да, я такое делал
 
подозреваю что нужен Task.Run но не хотелось бы уводить в другой поток кроме UI, а UI ж похоже не подойдет
таймер что ли
 
Подожди, момент
Смотри, что надо
1. На OnClosing делаешь e.Cancel=true.
Окей, теперь ты знаешь, что тебя хотят закрыть.
2. Если есть асинхронный clean-up модели, запускаешь его, в потоке этой самой модели
после его окончания просто делаешь Application.Shutdown. У тебя ещё раз вызовется OnClosing, и тут надо будет не отменять его
 
2 но ведь этот поток UI. я в нем планирую но он очевидно планируется раньше чем нормально отменится e.Cancel=true
 
@vitidev Смотрите, зачем вам e.Cancel == true? Очевидно, чтобы сделать clean-up и выйти, правильно?
Ой!
Перепутал, мы с вами на вы
Сорри!
Слишком много людей :-D
 
6:33 PM
это лишние сложности. ты вы это все глупости
 
@vitidev окей :)
 
if (_closeReason == CloseReason.NativeClose)
{
e.Cancel = true;
UIDispatcher.ExecuteAsync(
() =>
{
_vm.Cancel();
});
}

if (_closeReason == CloseReason.VmCloseRequested)
{
base.OnClosing(e);
}
 
@vitidev Выглядит правильно
 
вот я планирую отмену в UI потоке полагая что OnClosing дойдет до конца
но не работает. даже если перед vm.Cancel сделать паузу
 
UIDispatcher.ExecuteAsync же просто ставит в очередь?
Или что он делает?
 
6:35 PM
а нет. этот не чистый Post. момент
 
А, в этом может и быть загвоздка
Дело в том, что пока Closing "в полёте", e.Cancel = true не действует. Мы как бы всё ещё собираемся закрыться.
Поэтому нужно уйти на следующую итерацию цикла
Хоть через Dispatcher.BeginInvoke()
 
да. в этом. ExecuteAsync хитрый. он планирует в UI потоке,но если мы уже в нем то просто делает сразу
 
@vitidev Ааааа!
Тогда понятно
Он и убил-с виноват.
Изящнее было бы наверное так:
 
это awaitable обертка, а я как то не подумал про суффикс Async что он там для этого
 
if (_closeReason == CloseReason.NativeClose)
{
    e.Cancel = true;
    await Task.Yield(); // дожидаемся следующей итерации
    _vm.Cancel();
}
Должно сработать
 
6:43 PM
I have a trouble's
 
@webstackoverload Делитесь с нами!
 
@VladD Psycho trauble's...
 
@webstackoverload Ой, это выглядит серьёзнее
 
@VladD Yep, but i think u can help me with it
 
@webstackoverload Do you prefer English tonight?
 
6:45 PM
@VladD Nope but... i try to speak with english sometimes :)
 
You'd better be quick, as my time to leave is due in 10 minutes
 
@VladD ok but now i try to describe my problem in russian lang
 
Давайте :)
 
@VladD И так, все вы помните фильм про терминатора, который завис, от того что не смог выбрать задачу, и начал биться головой об трубу. У меня схожая ситуация, бывает так что я себе надумаю,
и занимаюсь, но, бывает момент когда я начинаю понимать что я занимаюсь не тем, и хочу заняться другим, в итоге становится выбор приоритетов что-ли - это как ребенку сказать выбери игрушку, но только одну, а их перед ним с 10-ток и все самые любимые. В итоге если я занимаюсь 2-3 делами - направлениями тогда - бывает что идет перегорание - либо работа замедляется от усталости - но проблема в том что нет потери интереса к той или инной области - что делать
 
А вы учитесь или работаете?
 
6:51 PM
Работаю - учиться я не люблю это скучно и сдерживало меня сильно )
 
Окей, ну тогда у вас же на работе есть какие-то задания, и они по идее держат вас в рамках?
 
@VladD Учиться в плане - ходить в интститут - писать в тетрдаь с доски и т д т п - это не учеба - учеба это интересное а его очень много :)
 
То есть вот я пишу, допустим, локализацию, и пока я её не допишу, переключаться нельзя никак. Даже если хочется.
 
@VladD Вот именно меня в рамках по идее держат не задания так как я их выпонляю достаточно - а компьютер в целом наверно
 
То есть вы не знаете покамест, хотите вы быть программистом или допустим панк-исполнителем?
 
6:55 PM
@VladD Дело в том что програмистом таким как ВЫ себе это представляете не хочу, допустим сидеть кодить - создавать функ класссы копаться постоянно в коде это не мое - НО ! Дело в том что если есть интересная задача - я быстро копаюсь в этом коде создаю классы и делаю все как нужно по феншую документации
 
(простите, надо бежать домой, надеюсь, другие участники чата помогут лучше)
 
Да не помогут, мне никто не поможет кроме математика или спалить ПК нужно и забыть это все как страшный сон ))))))))
 
 
2 hours later…
8:36 PM
@VladD 1) кажется в IReadOnlyCollection<T> GetSnapshot() нужно не RedirectToSelf делать, а проверять вызываемый поток на соотвествие - тем самым защищая от ошибок.
2) а ведь и в подписках нужно делать то же самое, а там уже как - кастомные add/remove монструозные будут.
3) целый поток нужно отдать коллекции. а если коллекций много? где та грань кому новый поток. а кто уживется с другими без проблем? Ведь события все будут в этом потоке
4) и если мы уж делаем метку (STA в имени) которая нам напомнит про необходимость перехода в поток....то так же мы напомним и про lockState
 
9:02 PM
@VladD я понял вашу позицию что внутри себя стаколлекция защищает себя приведением к нужному потоку вместо локов. А снаружи если нужно и подписаться и вычитать (более одного действия), то нужно не забыть войти в нужный поток. Вот меня беспокоит это "не забыть". И вопрос - нельзя ли разрулить такой подход локами не привязываясь к потоку вообще
 
 
1 hour later…
10:12 PM
@vitidev 1) Ну, это если вы хотите, чтобы клиенты были только из одного потока. Тогда уж и не Task, а синхронная функция. Ну это уже не принципиально, как вы решите, так и будет.
@vitidev 2) Да, подписки тоже нужно редиректить в поток коллекции, конечно. Многопоточные подписки = race blogs.msdn.microsoft.com/ericlippert/2009/04/29/…
 
1) нельзя же подписаться и запросить данные не войдя в поток снаружи коллекции.
 
@vitidev 3) Снова-таки это зависит от вашей задачи. У меня в одной Engine могли жить несколько коллекций. То есть коллекции делились между Engine'ами по близости семантики
@vitidev Ну, STA это так, для понятности. В реальности оно у меня называется как-нибудь CurrentTreatments
@vitidev 5) lock сам по себе не плох, но я сходу не вижу, как с ним легко сделать жёстко правильную и чистую семантику. может и можно?
@vitidev 6) Сложно как-то. Но если это ускоряет работу, почему бы и нет. Но это всё для lock'а, а мне вот всё же нравится STA
@vitidev Нет, не нужно! Публичные методы сами перебросят своё выполнение в нужный поток. В этом и фишка.
@vitidev Окей, можно сделать метод в коллекции:
 
мы подписываемся
мы забираем данные
если мы снаружи не синхронизируемся кто пока мы переходим от первого ко второму уже полетят данные Added, которые нам не нужны и нужно делать отдлеьные проверки
ну или наборот то же самое. оба вызова должны быть в одном потоке и не в абы каком
 
public async Task<IReadOnlyCollection<T>> GetInitialContentAndSubscribe(ItemAddedHandler h)
{
    await RedirectToSelf();
    added += h;
    return payload.ToList().AsEnumerable();
}
@vitidev Не, не так, смотрите код выше
 
ну плодить такие методы это перебор. мало ли какие события еще будут.
 
10:21 PM
вызывать можно откуда угодно
Ну а по-другому race
Хорошо, можно так:
 
>Ну а по-другому race

ну так а как же "сначала синхронизируемся с потом коллекци и потом уже делаем". ваши же слова
 
public async Task<IReadOnlyCollection<T>> GetInitialContentAndSubscribe(ItemAddedHandler hadded = null, ItemRemovedHandler hremoved = null, ItemChangedHandler hchanged = null)
{
    await RedirectToSelf();
    if (hadded != null)
        added += hadded;
    if (hremoved != null)
        removed += hremoved;
      if (hchanged != null)
        changed += hchanged;
    return payload.ToList().AsEnumerable();
}
и вызывать так:
await GetInitialContentAndSubscribe(hadded: OnAdded);
@vitidev То есть если мы перекинем наш код в Engine'овский поток, то можно не заморачиваться
То есть да, у нас два пути
Либо мы заставляем юзера переходить в нужный поток
и там пусть вычитывает и подписывается
а мы проверяем, в том ли он потоке, и если нет, швыряем в него исключением
это первый вариант
или второй вариант
мы даём ему все нужные комбинации (например, получить контент и подписаться) как Task
и пусть обращается к нам из любого потока, мы сами перебросим
в обоих случаях ему придётся немного подумать, чтобы не получить какой-нибудь race
 
ну вместо этой портянки кода лучше красивый хелпер-класс. Правда с событимя так красиво не очень получится. придется заменять их на кастомные
 
Это уже подробности имплементации :)
 
в этом и суть. я хочу чтобы было "не забыть"
чтобы класс клиент не обязан был постоянно лазить ко мне в кишки и смотреть "не хитрая ли я коллекция"
и не мудрить с конрактом типа этой портянки
 
10:29 PM
тогда лучше выставить Task-и?
тут уж точно забыть не даст компилятор
 
а чем они помогут
 
в первом можно вызвать неоттуда
@vitidev А они сами перекинут в нужный поток, юзеру не надо будет париться
а чтобы не было race'ов, ему будут даны только комбинации
 
list.Added+=
var items=list.GetItems()

внутри все будет в нужных потоках, только вот этот поток не непрерывен
 
@vitidev «внутри все будет в нужных потоках, только вот этот поток не непрерывен» — ?
 
list.Added+= внутри себя выполнится в нужном потоке
и var items=list.GetItems() тоже внутри в нужном
Но между ними в этом же потоке коллекции может произойти что угодно
 
10:32 PM
@vitidev Не-не-не, этого нам нужно избежать
Мы не дадим юзеру метод «просто подписаться» или «просто получить контент»
 
и у нас 2 решения. либо мы пишем портянку (выше метод) либо нужно "не забыть"
 
А только метод «подписаться и получить контент в одном флаконе»
ну так эту портянку мы прячем внутрь коллекции
 
а если нам только подписаться надо - еще одну портянку
 
Не, не должно быть надо
если надо только подписаться — скорее всего, это логическая ошибка
(Ordnung muss sein!)
 
навскидку - хочу активировать кнопку при появлении первого элемента. содержимое не интересует.
 
10:36 PM
@vitidev Тогда вам нужно получить контент и подписаться :) Если в контенте уже есть элементы, активируете кнопку и отписываетесь, иначе ждёте прихода ивента
 
ну если не держаться за дефолтные события с их += то можно наворотить варианты
 
11:20 PM
@vitidev угу, семантика += слишком слабая
 

« first day (892 days earlier)      last day (2139 days later) »