Специализация T GetFieldValue<T>(int ordinal)
От: Коваленко Дмитрий Россия http://www.ibprovider.com
Дата: 30.06.21 14:37
Оценка:
В .NET появилась пара типов DateOnly, TimeOnly, которые напрямую в DbDateReader не поддерживаются.

В том смысле, что в DbDateReader нет таких методов GetDateOnly, GetTimeOnly.

Но их можно поддерживать через виртуальный метод T GetFieldValue<T>(int ordinal).

В свете этой темы возник вопрос — как бы замутить такие специализации этого GetFieldValue<T>:

public override DateOnly GetFieldValue<DateOnly>(int ordinal)
{
 //....
}

public override TimeOnly GetFieldValue<TimeOnly>(int ordinal)
{
 //....
}




---
Я тут посмотрел, как такие вещи мутят другие

  Мутят они через if-ы
        public virtual T? GetFieldValue<T>(int ordinal)
        {
            if (IsDBNull(ordinal)
                && typeof(T).IsNullable())
            {
                return GetNull<T>(ordinal);
            }


            var type = typeof(T).UnwrapNullableType().UnwrapEnumType();
            if (type == typeof(bool))
            {
                return (T)(object)GetBoolean(ordinal);
            }

            //....

---
Можно как-то извернуться и таки сделать желаемую специализацию?
-- Пользователи не приняли программу. Всех пришлось уничтожить. --
Re: Специализация T GetFieldValue<T>(int ordinal)
От: BlackEric http://black-eric.lj.ru
Дата: 30.06.21 14:56
Оценка:
Здравствуйте, Коваленко Дмитрий, Вы писали:

КД>В .NET появилась пара типов DateOnly, TimeOnly, которые напрямую в DbDateReader не поддерживаются.


КД>В том смысле, что в DbDateReader нет таких методов GetDateOnly, GetTimeOnly.


КД>Но их можно поддерживать через виртуальный метод T GetFieldValue<T>(int ordinal).


КД>В свете этой темы возник вопрос — как бы замутить такие специализации этого GetFieldValue<T>:


Так у вас же полностью типизированный метод. Зачем if? Просто:
    GetDateTime(ordinal).Date;
https://github.com/BlackEric001
Re[2]: Специализация T GetFieldValue<T>(int ordinal)
От: Коваленко Дмитрий Россия http://www.ibprovider.com
Дата: 30.06.21 15:07
Оценка:
Здравствуйте, 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)
От: BlackEric http://black-eric.lj.ru
Дата: 30.06.21 15:18
Оценка:
Здравствуйте, Коваленко Дмитрий, Вы писали:

КД>Не догоняю, как мне это поможет реализовать T GetFieldValue<T> без if-ов (и их аналогов)?


КД>Другими словами — я хочу чтобы вызов (виртуального метода) reader.GetFieldValue<DateOnly>(index) транслировался в специализацию, а не в универсальный метод GetFieldValue<T>(...).


КД>Как такое замутить?


А, то я вопрос не дочитал. Похоже, что никак
https://github.com/BlackEric001
Re: Специализация T GetFieldValue<T>(int ordinal)
От: Sinclair Россия https://github.com/evilguest/
Дата: 30.06.21 16:00
Оценка: 15 (1)
Здравствуйте, Коваленко Дмитрий, Вы писали:

КД>В свете этой темы возник вопрос — как бы замутить такие специализации этого GetFieldValue<T>:

Простите, вопрос непонятен.
Вы пишете потомок DbDataReader для вашей особенной СУБД?
Или вы пишете приложение, которое должно работать с какой-то известной СУБД через DbDataReader?
Можете ли вы перейти от использования DbDataReader к конкретному классу типа SqliteDataReader, который из коробки имеет методы GetDateOnly/GetTimeOnly?
Если не можете, то почему?
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[3]: Специализация T GetFieldValue<T>(int ordinal)
От: Danchik Украина  
Дата: 30.06.21 17:15
Оценка: :)
Здравствуйте, Коваленко Дмитрий, Вы писали:

[Skip]

КД>Другими словами — я хочу чтобы вызов (виртуального метода) reader.GetFieldValue<DateOnly>(index) транслировался в специализацию, а не в универсальный метод GetFieldValue<T>(...).


КД>Как такое замутить?


Никак, но осталось чувство что ты что-то не то делаешь.
Re[4]: Специализация T GetFieldValue<T>(int ordinal)
От: Коваленко Дмитрий Россия http://www.ibprovider.com
Дата: 30.06.21 17:54
Оценка:
Здравствуйте, Danchik, Вы писали:

КД>>Другими словами — я хочу чтобы вызов (виртуального метода) reader.GetFieldValue<DateOnly>(index) транслировался в специализацию, а не в универсальный метод GetFieldValue<T>(...).


КД>>Как такое замутить?


D>Никак, но осталось чувство что ты что-то не то делаешь.


Да не, все то. По крайней мере, пока все получается.

----
Но, не будем отвлекаться.

Это выходит, что для каждого T вот эта портянка if-ов будет полностью компилироваться?

Только ради того, чтобы отработал один if?

Что-то как-то не очень красиво.
-- Пользователи не приняли программу. Всех пришлось уничтожить. --
Re[5]: Специализация T GetFieldValue<T>(int ordinal)
От: Danchik Украина  
Дата: 30.06.21 17:57
Оценка:
Здравствуйте, Коваленко Дмитрий, Вы писали:

[Skip]

КД>Что-то как-то не очень красиво.


Где-то проскакивало что JIT это дело сразу оптимизирует и ветвления отбрасывает. На 100% утверждать не могу.

Но все равно расскажи для чего тебе это.
Re[2]: Специализация T GetFieldValue<T>(int ordinal)
От: Коваленко Дмитрий Россия http://www.ibprovider.com
Дата: 30.06.21 18:33
Оценка: 108 (1)
Здравствуйте, Sinclair, Вы писали:

Это мой ADO.NET провайдер, для которого я пишу адаптер для EFCore. База — FB3.

S>Можете ли вы перейти от использования DbDataReader к конкретному классу типа SqliteDataReader, который из коробки имеет методы GetDateOnly/GetTimeOnly?


Отличный вопрос. Правда.

Начал объяснять, почему не могу.

И увидел, что таки могу

----
Нужно переопределить метод RelationalTypeMapping::GetDataReaderMethod

Работает

Но я таки уже запилил свою GetFieldValue с if-ами, тоже работает

----
Кстати, для Sqlite они могли бы тоже переопределить GetDataReaderMethod в мапперах для DateOnly/TimeOnly, но почему-то не сделали это.

Работают через GetFieldValue<T>.
-- Пользователи не приняли программу. Всех пришлось уничтожить. --
Отредактировано 30.06.2021 19:11 DDDX . Предыдущая версия . Еще …
Отредактировано 30.06.2021 18:34 DDDX . Предыдущая версия .
Re[6]: Специализация T GetFieldValue<T>(int ordinal)
От: Коваленко Дмитрий Россия http://www.ibprovider.com
Дата: 30.06.21 18:57
Оценка:
Здравствуйте, 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)
От: Danchik Украина  
Дата: 30.06.21 19:57
Оценка:
Здравствуйте, Коваленко Дмитрий, Вы писали:

[Skip]

КД>---

КД>А нужно было чуть получше покопаться и увидеть виртуальный метод RelationalTypeMapping.GetDataReaderMethod(), который можно переопредить.

КД>Собственно говоря, он там определен чуть выше статического


КД>В общем, всем спасибо!


Именно потому я и настаивал обьяснить для чего тебе надо. Хорошо что сам разобрался.
Re[6]: Специализация T GetFieldValue<T>(int ordinal)
От: rameel https://github.com/rsdn/CodeJam
Дата: 01.07.21 20:55
Оценка: 103 (5) +1
Здравствуйте, 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... считай что специализация для типов-значений
if (typeof(T) == typeof(bool) || typeof(T) == typeof(bool?))
{
    return (T)(object)GetBoolean(ordinal);
}


Для 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)
От: rameel https://github.com/rsdn/CodeJam
Дата: 01.07.21 20:59
Оценка: 16 (2)
Здравствуйте, Коваленко Дмитрий, Вы писали:

КД>Другими словами — я хочу чтобы вызов (виртуального метода) 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)
От: Коваленко Дмитрий Россия http://www.ibprovider.com
Дата: 02.07.21 04:48
Оценка:
Здравствуйте, rameel, Вы писали:

КД>>Другими словами — я хочу чтобы вызов (виртуального метода) reader.GetFieldValue<DateOnly>(index) транслировался в специализацию, а не в универсальный метод GetFieldValue<T>(...).


R>Если .NET5 то легко. Пишешь в начале метода

if (typeof(T) == typeof(DateOnly))
{
 Вызов твоего метода
}


R>Джит умеет такое оптимизировать


Вообще хотелось явно определить специализацию метода, а не полагаться на оптимизацию компилятора
-- Пользователи не приняли программу. Всех пришлось уничтожить. --
Re[5]: Специализация T GetFieldValue<T>(int ordinal)
От: Sinclair Россия https://github.com/evilguest/
Дата: 02.07.21 05:49
Оценка:
Здравствуйте, Коваленко Дмитрий, Вы писали:
КД>Вообще хотелось явно определить специализацию метода, а не полагаться на оптимизацию компилятора
Как я понимаю, в рамках существующего рантайма так не получится.
Если бы C# такое поддерживал, то внутри всё равно бы порождался один обобщённый метод со свитчем по типу, который бы уже раскидывал вызовы по конкретным перегрузкам.
Впрочем, такое всё ещё можно нарулить вручную при помощи разнообразных методик обработки AST и IL.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[3]: Специализация T GetFieldValue<T>(int ordinal)
От: Mystic Artifact  
Дата: 03.07.21 23:55
Оценка: 94 (3)
Здравствуйте, Коваленко Дмитрий, Вы писали:

КД>Кстати, для 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;
            }
        }
Re: Специализация T GetFieldValue<T>(int ordinal)
От: IT Россия linq2db.com
Дата: 07.07.21 16:12
Оценка:
Здравствуйте, Коваленко Дмитрий, Вы писали:

КД>Можно как-то извернуться и таки сделать желаемую специализацию?


Всегда можно закешировать результат if.
Если нам не помогут, то мы тоже никого не пощадим.
Re[2]: Специализация T GetFieldValue<T>(int ordinal)
От: Коваленко Дмитрий Россия http://www.ibprovider.com
Дата: 07.07.21 17:20
Оценка:
Здравствуйте, IT, Вы писали:

КД>>Можно как-то извернуться и таки сделать желаемую специализацию?


IT>Всегда можно закешировать результат if.


В смысле — Dictionary<Type,MethodInfo> ?

Ну это можно сразу, без всяких if, задействовать.

Речь же про то, чтобы явно заставить компилятор сгенерировать прямой вызов нужной специализации ...
-- Пользователи не приняли программу. Всех пришлось уничтожить. --
Re[3]: Специализация T GetFieldValue<T>(int ordinal)
От: Serginio1 СССР https://habrahabr.ru/users/serginio1/topics/
Дата: 07.07.21 19:59
Оценка:
Здравствуйте, Коваленко Дмитрий, Вы писали:

КД>Здравствуйте, 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)
От: IT Россия linq2db.com
Дата: 08.07.21 01:03
Оценка: +2
Здравствуйте, Коваленко Дмитрий, Вы писали:

IT>>Всегда можно закешировать результат if.

КД>В смысле — Dictionary<Type,MethodInfo> ?

Нет, это сурово. У тебя же дженерик, кешируй лямбду в переменной. По производительности будет мало отличаться.
Если нам не помогут, то мы тоже никого не пощадим.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.