Nano Hash - криптовалюты, майнинг, программирование

Невозможно изменить тип на допускающий значение NULL в универсальном методе

Я создаю универсальный конвертер

Вот пример кода универсального преобразователя

bool TryReaderParse<TType>(object data, out TType value)
{
    value = default(TType);
    Type returnType = typeof(TType);
    object tmpValue = null;

    if (returnType == typeof(DateTime))
    {
        tmpValue = StringToDatetime(data.ToString());
    }
    else if (returnType == typeof(DateTime?)) // THIS IF FIRES
    {
        tmpValue = StringToNullableDatetime(data.ToString());
    }

    value = (TType)Convert.ChangeType(tmpValue, returnType);  // THROWS
}

public DateTime? StringToNullableDatetime(string date)
{
    DateTime? datetime = null;
    if (!string.IsNullOrEmpty(date))
    {
        datetime = DateTime.Parse(date, new CultureInfo(Resources.CurrentCulture));
    }

    return datetime;
}

И вот как я его использую:

void foo()
{
    DateTime? date = null;
    TryReaderParse<DateTime?>("25/12/2012", out date);
}

Вызванное исключение говорит, что оно не может преобразовать из DateTime в Nullable<DateTime>. Поскольку метод создает и возвращает тип, допускающий значение NULL, почему приведение не выполняется?

В конце я хочу иметь DateTime, допускающий значение NULL, в этом конкретном примере.

edit Проблема в том, что метод StringToNullableDatetime возвращает Datetime?, а при приведении указано, что преобразование из Datetime невозможно.

Поскольку метод StringToNullableDatetime возвращает дату и время, допускающие значение NULL, как возможно, что Convert.ChangeType не может увидеть, что переданный аргумент имеет значение NULL?

Пс. Я читал ответы вроде this, которые делают противоположное (приведение из обнуляемого).


Ответы:


1

Вызванное исключение говорит, что оно не может преобразовать из DateTime в Nullable<DateTime>. Поскольку метод создает и возвращает тип, допускающий значение NULL, почему приведение не выполняется?

Хороший вопрос. Это не удается, потому что не существует такой вещи, как упакованное значение NULL. Когда вы конвертируете DateTime? в object, вы либо получаете пустую ссылку, если DateTime? было пустым, либо вы получаете заключенное в рамку значение, DateTime. Вы никогда не получите упакованную структуру, допускающую значение NULL; такого нет.

Следовательно, в этом поле вы получаете либо значение null, либо допустимое значение DateTime. Затем вы говорите Convert преобразовать это в DateTime, допускающее значение NULL, а Convert не знает, как это сделать.

Я советую вам полностью отказаться от этой линии атаки; этот код на грани злоупотребления дженериками. Каждый раз, когда вы переключаетесь на определенный тип универсального кода, ваш код перестает быть универсальным, и вы, вероятно, делаете это неправильно. Если вы хотите использовать метод «попробовать» для даты и времени, просто напишите это:

DateTime? TryReadDateTime(object data)
{
    ... return null if the object cannot be read as a datetime ...
}

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

DateTime? d = TryReadDateTime(data);
if (d != null) ...

Чем

DateTime d;
bool b = TryRead<DateTime>(data, out d);
if (b) ...
25.04.2012

2

Из документации эта строка выдаст ошибку, если:

значение равно null, а conversionType является типом значения

Nullable<T> - это структура и, следовательно, тип значения, поэтому вы не можете использовать этот вызов метода, если ваше значение равно null. Вы уже обрабатываете даты отдельно, так зачем вообще использовать ChangeType в таких случаях?

25.04.2012
  • отредактировал мой вопрос. Моя проблема в том, что я не могу вернуть дату и время, допускающее значение NULL. Строка Convert.ChangeType не может видеть, что переданный аргумент допускает значение NULL 25.04.2012

  • 3

    То, как взаимодействуют значения nullables, generics и boxing, довольно странно. Возможно, вам лучше определить два метода:

    bool TryReaderParse(object data, out TType value);
    bool TryReaderParse(object data, out TType? value) where TType : struct;
    

    Во втором методе ваш код может просто создать TType и без труда назначить его TType?.

    25.04.2012
  • Во-первых, метод не может быть перегружен только ограничениями. Во-вторых, если метод возвращает значение, допускающее значение NULL, тогда почему он также должен возвращать bool? Если вы собираетесь это сделать, то правильные подписи - T TryParseClass<T>(object data) where T : class и T? TryParseStruct<T>(object data) where T : struct. Нет необходимости в bool. 25.04.2012
  • Новые материалы

    Кластеризация: более глубокий взгляд
    Кластеризация — это метод обучения без учителя, в котором мы пытаемся найти группы в наборе данных на основе некоторых известных или неизвестных свойств, которые могут существовать. Независимо от..

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

    Частный метод Python: улучшение инкапсуляции и безопасности
    Введение Python — универсальный и мощный язык программирования, известный своей простотой и удобством использования. Одной из ключевых особенностей, отличающих Python от других языков, является..

    Как я автоматизирую тестирование с помощью Jest
    Шутка для победы, когда дело касается автоматизации тестирования Одной очень важной частью разработки программного обеспечения является автоматизация тестирования, поскольку она создает..

    Работа с векторными символическими архитектурами, часть 4 (искусственный интеллект)
    Hyperseed: неконтролируемое обучение с векторными символическими архитектурами (arXiv) Автор: Евгений Осипов , Сачин Кахавала , Диланта Хапутантри , Тимал Кемпития , Дасвин Де Сильва ,..

    Понимание расстояния Вассерштейна: мощная метрика в машинном обучении
    В обширной области машинного обучения часто возникает необходимость сравнивать и измерять различия между распределениями вероятностей. Традиционные метрики расстояния, такие как евклидово..

    Обеспечение масштабируемости LLM: облачный анализ с помощью AWS Fargate и Copilot
    В динамичной области искусственного интеллекта все большее распространение получают модели больших языков (LLM). Они жизненно важны для различных приложений, таких как интеллектуальные..