Указанный приведение недопустимо для универсального

У меня есть эта функция, которая проверяла текущее значение. Когда текущее значение (1-й параметр) равно нулю или пусто, оно использует значение по умолчанию, которое вы передаете (2-й параметр).

public static T ZeroNull<T>(object currentValue, T defaultValue)
{
    if (currentValue.Equals(DBNull.Value))
        return (T)defaultValue;
    else if (currentValue.Equals(string.Empty))
        return (T)defaultValue;
    else
        return (T)currentValue;
}

Приведенный выше код работает правильно, частично... Но когда я использую такой код, он выдает "Указанное приведение недействительно..."

float currValue = 20.1f;
int i = ZeroNull<int>(currValue, 0); // Specified cast is not valid

int i = ZeroNull<int>("10", 0); // Specified cast is not valid

Кто-нибудь может улучшить приведенный выше фрагмент кода? И почему компилятор выдает эту ошибку?

С уважением, Джесси


person klaydze    schedule 22.05.2015    source источник
comment
Проблема в том, что currValue представляет собой упакованное число с плавающей запятой (20.1f), и вы пытаетесь распаковать его в int, который недействителен. То же самое для 10   -  person chomba    schedule 22.05.2015
comment
Спасибо чомба, но почему он не выдает ошибку, когда я это делаю. codefloat currValue = 10.2f; codeint newCurrValue = (int)currValue; Я просто предполагаю, что у них одинаковая логика?   -  person klaydze    schedule 22.05.2015
comment
Это потому, что вы просто явно выполняете приведение между типами значений. Однако когда вы создаете блок типа значения, вам сначала нужно распаковать его в базовый тип.   -  person chomba    schedule 22.05.2015
comment
@klaydze, потому что в этом случае нет объектов - нет встроенного типа для распаковки.   -  person Panagiotis Kanavos    schedule 22.05.2015
comment
@xanatos Последняя строка возвращает (T)currentValue   -  person Yuval Itzchakov    schedule 22.05.2015
comment
Очень странно, что функция меняет исходный тип на тип значения по умолчанию, что может вызвать ошибку времени выполнения.   -  person Eric    schedule 22.05.2015
comment
@chomba Спасибо за информацию. Любое предложение по улучшению приведенного выше кода? Я просто предполагаю, что моя функция выше совпадает с кодом в моем комментарии. :)   -  person klaydze    schedule 22.05.2015
comment
На самом деле это плохая идея, чтобы один и тот же метод пытался делать две вещи - возвращать значение по умолчанию и преобразовывать типы. Как вы собираетесь его использовать? Почему бы просто не использовать ?? ? У вас есть DataTable, в котором вместо числовых типов используются строки?   -  person Panagiotis Kanavos    schedule 22.05.2015
comment
@PanagiotisKanavos Вот как я использую этот метод. Вы также можете изменить свойство на Nullable. _defaultMinValue = PFDMSDataCollection.ZeroNull<double>(datarow["dblDefaultMinValue"], 0.0); _defaultMaxValue = PFDMSDataCollection.ZeroNull<double>(datarow["dblDefaultMaxValue"], 0.0);   -  person klaydze    schedule 22.05.2015


Ответы (2)


Вы можете попробовать использовать IConvertible Интерфейс, так что он по крайней мере будет работать для типов, которые его реализуют. Остерегайтесь, это может по-прежнему вызывать исключения для типов, которые его не используют, но для ваших преобразований все отлично:

public static T ZeroNull<T>(object currentValue, T defaultValue)
{
    if (currentValue.Equals(DBNull.Value))
        return (T)defaultValue;
    else if (currentValue.Equals(string.Empty))
        return (T)defaultValue;
    else
        return (T)Convert.ChangeType(currentValue,typeof(T));
}

Что касается вашего приведения к int из float: вы пытаетесь преобразовать упакованный тип - он был помещен в коробку, когда вы вызвали свой метод, который эффективно преобразовал его в объект. Типы в штучной упаковке могут быть возвращены только самим себе. Поскольку приведение к int не одного типа, оно не сработает. Чтобы воспроизвести без дженериков, попробуйте это, он также выдаст InvalidCastException:

float currValue = 20.1f;

object yourValue = currValue;
int i = (int) yourValue;  //throws as well
person Marwie    schedule 22.05.2015
comment
Спасибо за ваше предложение. Я попробовал это и отлично работает по моему текущему требованию. Я буду придерживаться вашего предложения до тех пор, пока снова не столкнусь с другим исключением. :) - person klaydze; 22.05.2015

Проблема, с которой вы столкнулись, заключается в том, что вы не можете привести String к типу int, что вы и пытаетесь сделать, приведя currValue к T, когда T имеет тип int.

Для выполнения такой операции вам придется использовать Convert.ToInt32 или Int.Parse. любой из которых подорвет ваш текущий дизайн.

person Steve Lillis    schedule 22.05.2015