Pull to refresh
4
0

Пользователь

Send message
Ох какой винегрет…
аргументы про надёжность дронов

В этом вобщем-то и смысл всех этих глупых сертификаций.Что не должны летать по городу всякие поделки
что (вменяемые) владельцы дронов понимают, что делают и летают там, где людей нет

В этом вобщем-то и смысл всех этих нелепых регистраций, чтобы абы кто не летал как ему вздумается и полностью осознавал свою ответственность
что шанс попасть под машину гораздо выше

про шанс упасть с высоты 100 метров кому-то именно на голову

Поделитесь ссылочками на исследования?
Если по вине неизвестного вам на голову посреди улицы прилетит 10 килограммовая железка, то ограничения не покажутся такими уж глупыми.

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

Читаем по ссылке:

Угу, читаем прям вот следующий абзац
Use the Dispose method of this interface to explicitly release unmanaged resources in conjunction with the garbage collector

Не освободим, если это struct. Я это уже говорил, но вы решили об этом забыть.

Попробуйте прочитать весь абзац из которого вырвана эта фраза и понять к чему она относится. Не вижу смысла в очередной раз повторяться.
Антипаттерн — это использовать публичный протокол, который требует явной очистки ресурсов, и потом эти ресурсы не очищать. Также антипаттерн — это надеяться на детали реализации, что кто-то за вами там что-то почистит когда-нибудь.

А я разве где-то писал о том, что явно диспозить объект не нужно? Я говорил об исходном назначении паттерна, описанного в статье msdn.
Касательно структур с unmanaged: да, иногда очень надо для совсем критичных мест и писаться этот участок должен очень аккуратно, т.к. поломать стейт unmanaged ресурса очень легко, если он не весь идемпотентный и требуется хранить даже минимально мутабельный стейт внутри объекта, владеющего unamanaged ресурсом. Для общего случая работы с Unmanaged это скорее антипаттерн.

Пример
Before — был какой-то метод с кучей вызовов в Unmanaged
After — кто-то его порефакторил. Визуально — вполне легальный рефакторинг без претензий компилятора.
Т.е. использование unmanaged в структуре накладывает еще и жесткие ограничения на работу с ней через ref (о которых компилятор не парится), а не только на необходимость вызвать Dispose.
ref struct эту проблему тоже не решает, но хотя бы не дает навесить интерфейс и вызывать методы через боксинг (что тоже кораптит стейт), что уже лучше.

    public unsafe struct CustomStream : IDisposable
    {
        private int _size;
        private int _currentPos;
        private IntPtr _ptr;
        private bool _isDisposed;

        public CustomStream(int initialSize)
        {
            _currentPos = 0;
            _size = initialSize;
            _ptr = Marshal.AllocHGlobal(initialSize);
            _isDisposed = false;
        }
        
        public void Append(byte data)
        {
            if (_currentPos < _size)
            {
                Marshal.WriteByte(_ptr, _currentPos, data);
                // тут вот мы изменяем наш стейт
                _currentPos++;
            }
        }

        public void Dispose()
        {
            if (!_isDisposed)
            {
                Marshal.FreeHGlobal(_ptr);
                _isDisposed = true;
            }
        }
    }

    public class Example
    {
        public void Before()
        {
            using (CustomStream stream = new CustomStream(1024))
            {
                stream.Append(0);
                stream.Append(1);
                // всё ОК
            }
        }

        public void After()
        {
            using (CustomStream stream = new CustomStream(1024))
            {
                WriteHeaderBlock(stream);
                WriteClosingBlock(stream); // вот тут уже кораптим стейт
            }
        }

        public void WriteHeaderBlock(CustomStream stream)
        {
            stream.Append(0);
        }

        public void WriteClosingBlock(CustomStream stream)
        {
            stream.Append(1);
        }
    }


Еще раз о том, что написано у автора

Тут согласен — формулировка неверная, но лишь отчасти (если ресурс используемый в этой ref структуре не обернут в IDisposable объект хотя и абзац был про вообще, а не структуры в частности). Т.е. если там FileStream, то верно, а если нативный буфер, то нет.
Мне кажется, вы совершенно проигнорировали мою исходную позицию, и вместо этого теперь пытаетесь сказать мне то же самое

Я отвечал именно на эту вот фразу:
MSDN намекает на то, что Dispose нужен мягко говоря для другого — не просто что-то закрыть, а освободить неуправляемые ресурсы, которые иначе освобождены никогда не будут

C этим тезисом я не совсем согласен — в msdn о другом, т.к. если посмотреть на пример в статье, то по нему видно, что даже не вызвав Dispose мы всё равно с течением времени освободим ресурс, но недетерминировано (разумеется, при корректной реализации паттерна, приведенной в качестве примера). В msdn-статье нет ни слова о структурах, т.к. для обычных паттерн юзается не по назначению (и, вообще, зачем нужны явные umanaged в структуре(?), явный антипаттерн и источник проблем за редкими исключениями), а ref появились уже позже и тут вызов Dispose обязателен.
Вобщем, я думаю, вопрос исчерпан.

почему 'не совсем согласен'
Немного поясню почему «не совсем согласен»: всё-таки могут быть edge-кейсы, когда ресурс действительно может стать zombie. Если он уплыл в GC/2 и долго там не собирался мусор, а потом приложение завершается, но финализаторы не отрабатывают в установленный таймаут, а ресурсом был ком-объект через DCOM (вне процесса). Или сайт в пуле IIS хостится, а umnaged-ресурс не CFO. Но это скорее нештатные кейсы.

Не будет. Сделали специальную оптимизацию в обход спецификации: https://stackoverflow.com/questions/2412981/if-my-struct-implements-idisposable-will-it-be-boxed-when-used-in-a-using-statem/2413844#2413844

Ещё раз про статью в msdn: там описано исходное назначение паттерна — детерминированное освобождение ресурса. О том что stack-only struct поддерживает только явную очистку захваченных ресурсов у автора также указано в статье, но в msdn не об этом. А для приведённого вами примера характерно использование Dispose для работы с управляемыми ресурсами через Dispose (например, локальный захват локера на запись и его высвобождение в Dispose). В том же случае, если вы ссылаетесь на неуправляемый ресурс в структуре (обычной как в примере, не ссылочной), то это как минимум может привести к нарушению семантики владения ресурсом при копировании структуры (неявном опять таки). Да, согласен, в данном случае финализатора нет и есть хорошая возможность выстрелить в ногу из-за отсутствия финализатора и Dispose тут как бы решает проблему, но, тем ни менее, это не отменяет исходное назначение паттерна.

Пардон, "детерминированного освобождения ресурсов"

У автора правильно написано. Освобождение ресурса может быть написано в финализаторе без всякого Dispose. Паттерн нужен в первую очередь для детерминированной очистки ресурсов.

удалить созданные локальные миграции
подтянуть к себе изменения из репозитория, куда остальные коллеги с высоким приоритетом уже влили свои миграции
создать локальную миграцию и залить получившиеся изменения обратно в git

Это мягко говоря не всегда так. Вернее, так делать может понадобиться только в том случае, если 2 разработчика вливают конфликтующие изменения модели. Во всех остальных случаях достаточно добавить пустую миграцию для корректировки снэпшоты модели в БД. Посмотрите внимательно этот гайд (https://m.habr.com/ru/post/277915/), там описан подход.
Добавление пустой миграции, имхо, предпочтительнее головняка с пересозданием миграцией, т. к. уменьшается вероятность ошибки при перегенерации (могут быть и ручные правки внутри). Всё пустые миграции с ходом времени можно удалять из кода без последствий (достаточно, чтобы после пустой миграции появилась хотя бы одна новая, которая сохранит актуальный снэпшот модели).

В целом, так и есть, но тем ни менее в Delphi и том же WinForms была огромная инфраструктура по сравнению с существующими API браузеров + UI библиотек. Всё делалось ОЧЕНЬ быстро. И компонентная база содержала кучу компонент практически на любые случаи. Это от вендора фреймворка + дополнительная куча компонент, API которых был в едином стиле с фреймворком в большинстве случаев. Зоопарка ощутимо было меньше.

В итоге эмулировать десктоп в вебе сложно и невостребовано.

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

П, С. Очень уважаю React и, в целом, не испытываю большого скепсиса по поводу современного веба, но то как выглядят изнутри многие современные веб «приложения» в сравнении с олдовыми винформами порой удручает.
ИМХО, имеет смысл упомянуть в статье об этом ограничении. TPT не такая уж редко используемая конфигурация.
// Mapped to Table A
public class A {
  public string MappingName {get; set;}
}

//Mapped to Table B
public class B: A {
  public long OrderIndex {get; set;}
}

работаем с «B»

Delete from {x} where {x.MappingName} = 'Custom'


И тут выходит, что потребуется фактически парсить Sql, т.к. от конкретного оператора
зависит преобразование.

в этот delete придётся инжектить еще операторы:

delete t1 
from B t1 
inner join A t2 
on A.Id = B.Id 
where t2.MappingName = 'Custom'

delete
from A
where MappingName = 'Custom'


Для общего случая с TPT, имхо, не применимо.

Наколько я понял по исходникам, есть поддержка TPH и TPC, но не TPT.
Попробуйте ещё его релизовать.

TypeScript, это типизация следующего поколения

А можно поподробнее? Очень любопытно.

2

Information

Rating
Does not participate
Registered
Activity