Здравствуйте, sergeya, Вы писали:
НС>>А вот в случае с TryFormat это не так и смысла переусложнять API нет. S>Что может быть проще decimal.FormatTo(stringBuilder)?
Унутре decimal форматируется в буфер некоей фиксированной длины as is, т.к. самое длинное представление decimal заранее известно.
Затем берется заданная извне точность и по ней округляется (укорачивается или дополняется 0-ми в дроби) результат.
На выходе — само представление плюс получившееся кол-во символов этого представления.
После этого символы копируются в целевой буфер, но их кол-во уже известно.
Здравствуйте, sergeya, Вы писали:
S>Поэтому похоже что сначала печать выполняется в промежуточный буфер гарантированно достаточного размера, S>и только после этого выполняется попытка скопировать результат в буфер-приемник.
Так и есть.
Единственно, чего не хватает в этом АПИ — это выставить наружу такой промежуточный буфер.
Надеюсь, когда-нить сподобятся...
А сейчас у меня в либах самописные вообще все форматтеры под все числовые типы и большинство представлений даты.
S>А тут уже есть вся информация о том, сколько места не хватило.
В текущем АПИ тут не избежать повторного форматирования, если места не хватило, поэтому всё еще лажа.
S>Код из приведенного тобой исходника:
Походу, еще не GC-free для double.
Если экспонента небольшая, ИМХО, стоит переводить в decimal и форматировать уже его, там GC-free реализация.
Здравствуйте, Ночной Смотрящий, Вы писали:
S>>Но меня смущает не отсутсвие расчитанного размера, а двойная работа — если размера буфера не хватит, придется выполнять форматирование повторно с самого начала. НС>Вот смотри — для базовых типов размер буфера неизвестен заранее для чисел и енумов.
Для числовых данных и дат известен максимальный размер.
И там в любом случае происходит форматирование сначала в промежуточный буфер.
НС>В обоих случаях посчитать размер буфера сопроставимо по затратам с собственно форматированием.
Ес-но.
Т.е. достаточно выставить уже имеющийся унутре буфер наружу, чтобы юзать его как-то так.
internal ref struct NumberBuffer {
public int Scale;
public bool IsNegative;
private byte _b0;
private byte _b1;
...
}
НС>Ключевое отличиче — в случае конвертера объемы могут быть очень большими, заранее непредсказуемого размера. А вот в случае с TryFormat это не так и смысла переусложнять API нет.
Переусложнение АПИ vs переусложнение сценариев. ))
На сейчас сценарий вокруг TryFormat не просто переусложнён, он де-факто на грани невостребованности.
Здравствуйте, vdimas, Вы писали: V>Но к чему тогда относилось твоё "теперь да", если ты там Span инициализировал?
Ну, мне показалось, что поддержку инициализации Span из stackalloc прикрутили в 7.3, а сам Span появился в 7.0.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Sinclair, Вы писали:
V>>Но к чему тогда относилось твоё "теперь да", если ты там Span инициализировал? S>Ну, мне показалось, что поддержку инициализации Span из stackalloc прикрутили в 7.3, а сам Span появился в 7.0.
Я подключился к проекту на .Net Core в актуальность C# версии 7.2, и сразу "подсел" на эту конструкцию и всё вокруг Span.
Здравствуйте, Sinclair, Вы писали:
V>>А где ты видел Span до версии 7.2? S>В основном в блогах. Его же начали прикручивать ещё до поддержки ref struct.
Я тебе более того скажу. Его бэкпортировали в NuGet-пакет System.Memory ещё до того, как сам тип появился в .NET Core 2.1 и языковая поддержка ref struct появилась в C# 7.2 (трёхкомпонентный Slow Span vs. двухкомпонентный Fast Span).
Собственно, его и сейчас приходится оттуда брать, потому что в .NET Standard-то его ещё не завезли. И использовать его можно хоть на C# 2.0 даже под netstandard1.1 или net45.
Здравствуйте, Sinclair, Вы писали:
V>>А где ты видел Span до версии 7.2? S>В основном в блогах. Его же начали прикручивать ещё до поддержки ref struct.
А у тебя вообще такая конструкция компиллируется?
Span<byte> s = new Span<char>(stackalloc char[42], 42);
error CS1525: Invalid expression term 'stackalloc'
А такая?
Span<byte> s;
s = stackalloc byte[42];
error CS8353: A result of a stackalloc expression of type 'Span<byte>' cannot be used in this context because it may be exposed outside of the containing method
Из доки:
The keyword is valid only in local variable initializers.
Например, в тернарных операторах работает чудесно, если результат тернарных операторов инициализирует переменную.
Здравствуйте, vdimas, Вы писали:
V>Здравствуйте, Sinclair, Вы писали:
V>>>А где ты видел Span до версии 7.2? S>>В основном в блогах. Его же начали прикручивать ещё до поддержки ref struct.
V>А у тебя вообще такая конструкция компиллируется? V>
V>Span<byte> s = new Span<char>(stackalloc char[42], 42);
V>
Неа Я от неё ожидал просто возврата char*, авотхрен.
Можно как-то так
V>А такая? V>
V>Span<byte> s;
V>s = stackalloc byte[42];
V>
V>
V>error CS8353: A result of a stackalloc expression of type 'Span<byte>' cannot be used in this context because it may be exposed outside of the containing method
error CS8352: Cannot use local 's' in this context because it may expose referenced variables outside of their declaration scope
V>Из доки: V>
V>The keyword is valid only in local variable initializers.
V>Например, в тернарных операторах работает чудесно, если результат тернарных операторов инициализирует переменную.
Я так понял, это by design.
Вот так работает:
unsafe private static Span<char> Test(int number)
{
Span<char> s;
if (number < 100)
{
char* t = stackalloc char[number];
s = new Span<char>(pointer: t, number);
}
else
s = new char[number];
return s;
}
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Sinclair, Вы писали:
S>Вот так работает: S> char* t = stackalloc char[number]; S> s = new Span<char>(pointer: t, number);
Ес-но, "встроенная защита" обходится одной строкой кода.
С другой стороны, требует явный unsafe, т.е. кое-какой смысл в этом, наверное, есть.
Мол, специально стрелять в ногу запретить не можем, но хоть подстрахуем от случайных самострелов.
Здравствуйте, fmiracle, Вы писали:
F>Здравствуйте, Kolesiki, Вы писали:
K>>Зачем вам сегодня переносимость? Кому, что и куда переносить? ЧТО переносить и чего нет в других платформах?
F>Самый наибанальнейший пример — хостить asp.net сервер под линуксом (дешевле и доступнее хостинг), а разрабатывать под виндами и спокойно его и там и там запускать. F>Весьма удобно, кстати.
Пикус в том, что сам Линукс — пародия на то, чем должна быть ОС. Бегают все с линуксом, будто это панацея какая-то! А на деле — то же решето, причём состав ОС — полный бардак и анархия. Администрировани Линупса — вообще отдельный дзен, постигаемый ГОДАМИ. Мне в пень не упёрлись траханья с "just for fun" системой, я хочу "интыпрайз" и более-менее обкатанную систему + ВСЕ привычные программы, написанные для венды за 20 лет существования. Мне не нужны недописанные, недоотлаженные куски говна, которые кто-то собирает в один дистр и гордо продаёт. Поэтому категорически не понимаю этого "облинупсятивания" ИТ: запомните — "не винда" — это не одно и то же, что "линукс". Можете ненавидеть венду, но ничего ЛУЧШЕ вы(мамкины хэйтеры) всё равно предложить не можете. Даже сами сознаётесь — "а разрабатывать под виндами" — это с чего бы?? Да с того, что и писать, и запускать, надо на одной системе. Бонус такого подхода — что потенциальные грабли ловятся легче в подобных системах, а не винегрете "венда-линупс".
Core — оно как бы пытается решать проблемы "одновендового дотнета", но проблемы — они не в том, что слишком "обвендузятили рантайм", а в самом подходе к переносимости. переносим должен быть ИСХОДНЫЙ КОД. Всё. А то, что вместо этого сгенерили "нигде не исполнимый псевдокод" — это уже провал горе-архитекторов. К тому же, Core вылезает слишком поздно, имея на плечах давящий груз совместимости. Только вот беда — нельзя сделать "хорошо" и "совместимо" одновременно. В этом плане D не побоялся иметь breaking changes — он просто отмёл весь шлак и ввёл фичи без оглядки на старьё. Зато теперь это неплохой, развитый язык, причём имеющий и вендовый, и линуксовый компилятор (прикинь!). Кодеры Core просто взвыли от зависти.