Здравствуйте, Коваленко Дмитрий, Вы писали:
КД>В .NET появилась пара типов DateOnly, TimeOnly, которые напрямую в DbDateReader не поддерживаются.
КД>В том смысле, что в DbDateReader нет таких методов GetDateOnly, GetTimeOnly.
КД>Но их можно поддерживать через виртуальный метод T GetFieldValue<T>(int ordinal).
КД>В свете этой темы возник вопрос — как бы замутить такие специализации этого GetFieldValue<T>:
Так у вас же полностью типизированный метод. Зачем if? Просто:
Здравствуйте, BlackEric, Вы писали:
КД>>В том смысле, что в DbDateReader нет таких методов GetDateOnly, GetTimeOnly.
КД>>Но их можно поддерживать через виртуальный метод T GetFieldValue<T>(int ordinal).
КД>>В свете этой темы возник вопрос — как бы замутить такие специализации этого GetFieldValue<T>:
BE>Так у вас же полностью типизированный метод. Зачем if? Просто: BE>
BE> GetDateTime(ordinal).Date;
BE>
Не догоняю, как мне это поможет реализовать T GetFieldValue<T> без if-ов (и их аналогов)?
Другими словами — я хочу чтобы вызов (виртуального метода) reader.GetFieldValue<DateOnly>(index) транслировался в специализацию, а не в универсальный метод GetFieldValue<T>(...).
Как такое замутить?
-- Пользователи не приняли программу. Всех пришлось уничтожить. --
Re[3]: Специализация T GetFieldValue<T>(int ordinal)
Здравствуйте, Коваленко Дмитрий, Вы писали:
КД>Не догоняю, как мне это поможет реализовать T GetFieldValue<T> без if-ов (и их аналогов)?
КД>Другими словами — я хочу чтобы вызов (виртуального метода) reader.GetFieldValue<DateOnly>(index) транслировался в специализацию, а не в универсальный метод GetFieldValue<T>(...).
КД>Как такое замутить?
Здравствуйте, Коваленко Дмитрий, Вы писали:
КД>В свете этой темы возник вопрос — как бы замутить такие специализации этого GetFieldValue<T>:
Простите, вопрос непонятен.
Вы пишете потомок DbDataReader для вашей особенной СУБД?
Или вы пишете приложение, которое должно работать с какой-то известной СУБД через DbDataReader?
Можете ли вы перейти от использования DbDataReader к конкретному классу типа SqliteDataReader, который из коробки имеет методы GetDateOnly/GetTimeOnly?
Если не можете, то почему?
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[3]: Специализация T GetFieldValue<T>(int ordinal)
[Skip]
КД>Другими словами — я хочу чтобы вызов (виртуального метода) reader.GetFieldValue<DateOnly>(index) транслировался в специализацию, а не в универсальный метод GetFieldValue<T>(...).
КД>Как такое замутить?
Никак, но осталось чувство что ты что-то не то делаешь.
Re[4]: Специализация T GetFieldValue<T>(int ordinal)
Здравствуйте, Danchik, Вы писали:
КД>>Другими словами — я хочу чтобы вызов (виртуального метода) reader.GetFieldValue<DateOnly>(index) транслировался в специализацию, а не в универсальный метод GetFieldValue<T>(...).
КД>>Как такое замутить?
D>Никак, но осталось чувство что ты что-то не то делаешь.
Да не, все то. По крайней мере, пока все получается.
----
Но, не будем отвлекаться.
Это выходит, что для каждого T вот эта портянка if-ов будет полностью компилироваться?
Только ради того, чтобы отработал один if?
Что-то как-то не очень красиво.
-- Пользователи не приняли программу. Всех пришлось уничтожить. --
Re[5]: Специализация T GetFieldValue<T>(int ordinal)
Это мой ADO.NET провайдер, для которого я пишу адаптер для EFCore. База — FB3.
S>Можете ли вы перейти от использования DbDataReader к конкретному классу типа SqliteDataReader, который из коробки имеет методы GetDateOnly/GetTimeOnly?
Здравствуйте, Danchik, Вы писали:
D>[Skip]
КД>>Что-то как-то не очень красиво.
D>Где-то проскакивало что JIT это дело сразу оптимизирует и ветвления отбрасывает. На 100% утверждать не могу.
D>Но все равно расскажи для чего тебе это.
Ну как для чего, хотел заставить EFCore вместо "селектора" в виде GetFieldValue напрямую юзать нужный метод DataReader-а.
Место, где они выбирают метод для чтения значения колонки, я нашел — статический RelationalTypeMapping.GetDataReaderMethod(Type).
Понял, что они для неопознанных типов данных юзают DbDataReader.GetFieldValue<T>. Запилил его и он мне не понравился. О чем я тут и написал.
---
А нужно было чуть получше покопаться и увидеть виртуальный метод RelationalTypeMapping.GetDataReaderMethod(), который можно переопредить.
Собственно говоря, он там определен чуть выше статического
В общем, всем спасибо!
-- Пользователи не приняли программу. Всех пришлось уничтожить. --
Re[7]: Специализация T GetFieldValue<T>(int ordinal)
[Skip]
КД>--- КД>А нужно было чуть получше покопаться и увидеть виртуальный метод RelationalTypeMapping.GetDataReaderMethod(), который можно переопредить.
КД>Собственно говоря, он там определен чуть выше статического
КД>В общем, всем спасибо!
Именно потому я и настаивал обьяснить для чего тебе надо. Хорошо что сам разобрался.
Re[6]: Специализация T GetFieldValue<T>(int ordinal)
Здравствуйте, Danchik, Вы писали:
D>Где-то проскакивало что JIT это дело сразу оптимизирует и ветвления отбрасывает. На 100% утверждать не могу.
Именно эту портянку JIT с оптимизировать не сможет.
Что он может сейчас для generic-класс/метода на вскидку:
typeof(T).IsValueType — константа для JIT, а соотвественно все не нужные ветвления для ссылочных или типов-значений устраняются на ура, к ним же относятся и такие методы как RuntimeHelpers.IsReferenceOrContainsReferences<T>() и Unsafe.SizeOf<T>() typeof(T).IsAssignableTo(typeof(...))/typeof(T).IsAssignableFrom(typeof(...)) — также являются интринскиками JIT и определены во время компиляции метода. К константам времени компиляции JIT теперь также относятся и статические readonly поля.
Все это верно для .NET 5.0, для 6 список еще пополнится вроде как.
ЗЫ. Всю эту портянку можно было написать правильно и тогда JIT устранил бы все не нужное
Взять хотя бы вот это:
if (type == typeof(bool))
{
return (T)(object)GetBoolean(ordinal);
}
Enum не может быть bool, также как и char, DateTime, DateTimeOffset и прочее, а значит вот это строчка связала руки JIT-у и зарубила все возможные оптимизации:
var type = typeof(T).UnwrapNullableType().UnwrapEnumType();
И такое условие и многие другие с легкостью могли быть с оптимизированы, если бы писали с оглядкой на возможные оптимизации JIT... считай что специализация для типов-значений
Для Enum и nullable-enum можно завести вспомогательный generic-класс TypeHelper<T>.IsByte и прочее, тогда все остальное тоже свернется еще на этапе компиляции.
Сейчас там 24 условия, из которых при правильном написании осталось бы только парочка для ссылочных типов (byte[] и DBNull), а для value-типов все проверки были бы устранены полностью.
... << RSDN@Home 1.0.0 alpha 5 rev. 0>>
Re[3]: Специализация T GetFieldValue<T>(int ordinal)
Здравствуйте, Коваленко Дмитрий, Вы писали:
КД>Другими словами — я хочу чтобы вызов (виртуального метода) reader.GetFieldValue<DateOnly>(index) транслировался в специализацию, а не в универсальный метод GetFieldValue<T>(...).
Если .NET5 то легко. Пишешь в начале метода
if (typeof(T) == typeof(DateOnly))
{
Вызов твоего метода
}
Джит умеет такое оптимизировать
... << RSDN@Home 1.0.0 alpha 5 rev. 0>>
Re[4]: Специализация T GetFieldValue<T>(int ordinal)
Здравствуйте, rameel, Вы писали:
КД>>Другими словами — я хочу чтобы вызов (виртуального метода) reader.GetFieldValue<DateOnly>(index) транслировался в специализацию, а не в универсальный метод GetFieldValue<T>(...).
R>Если .NET5 то легко. Пишешь в начале метода
if (typeof(T) == typeof(DateOnly))
{
Вызов твоего метода
}
R>Джит умеет такое оптимизировать
Вообще хотелось явно определить специализацию метода, а не полагаться на оптимизацию компилятора
-- Пользователи не приняли программу. Всех пришлось уничтожить. --
Re[5]: Специализация T GetFieldValue<T>(int ordinal)
Здравствуйте, Коваленко Дмитрий, Вы писали: КД>Вообще хотелось явно определить специализацию метода, а не полагаться на оптимизацию компилятора
Как я понимаю, в рамках существующего рантайма так не получится.
Если бы C# такое поддерживал, то внутри всё равно бы порождался один обобщённый метод со свитчем по типу, который бы уже раскидывал вызовы по конкретным перегрузкам.
Впрочем, такое всё ещё можно нарулить вручную при помощи разнообразных методик обработки AST и IL.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[3]: Специализация T GetFieldValue<T>(int ordinal)
Здравствуйте, Коваленко Дмитрий, Вы писали:
КД>Кстати, для Sqlite они могли бы тоже переопределить GetDataReaderMethod в мапперах для DateOnly/TimeOnly, но почему-то не сделали это. КД>Работают через GetFieldValue<T>.
Работать с типами в именах которых присутствует слово Only — это как в говно макнуться. За 20 лет написали столько рекомендаций по именованиям, а самим строго им не следовать эти же 20 лет... Ну и вообще с датами там всё плохо, начиная с DateTime, который не может распарсить ("вместить") дату RFC.
Вообще по теме — как я понял, стоит поддерживать все вышеизложенные варианты.
Что касается специализаций — то их нет. Точнее говоря есть в таком вот дубовом виде. Зато в защиту скажу — что специализация в таком виде позволяет гораздо больше чем просто провека типа по T. На такие специальные вещи замахаешься язык расширять.
Классика — это реализация метода List::Clear:
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Clear()
{
_version++;
if (RuntimeHelpers.IsReferenceOrContainsReferences<T>()) // <<< вот она адская специализация
{
int size = _size;
_size = 0;
if (size > 0)
{
Array.Clear(_items, 0, size); // Clear the elements so that the gc can reclaim the references.
}
}
else
{
_size = 0;
}
}
Здравствуйте, Коваленко Дмитрий, Вы писали:
КД>Здравствуйте, IT, Вы писали:
КД>>>Можно как-то извернуться и таки сделать желаемую специализацию?
IT>>Всегда можно закешировать результат if.
КД>В смысле — Dictionary<Type,MethodInfo> ?
КД>Ну это можно сразу, без всяких if, задействовать.
КД>Речь же про то, чтобы явно заставить компилятор сгенерировать прямой вызов нужной специализации ...
public virtual T? GetFieldValue<T>(int ordinal,Func<int,T?> method)
{
if (method!=null)
return method(ordinal);
}
и солнце б утром не вставало, когда бы не было меня
Re[3]: Специализация T GetFieldValue<T>(int ordinal)