Specified cast not valid with generic
Asked Answered
D

2

7

I have this function that checked the current value. When the current value (1st parameter) is null or empty, then it uses the default value you pass (2nd paramter)

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;
}

The code above is working properly, partially... But when I use the code like this, it throws an "Specified cast is not valid..."

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

Anybody can improve the above code snip? And why the compiler throw this error?

Regards, Jessie

Deepfry answered 22/5, 2015 at 6:46 Comment(9)
The problem is that currValue is a boxed float (20.1f) and your trying to unbox to a int which isn't valid. The same goes for "10"Sit
Thanks chomba, but why it's not throwing an error when I do this. codefloat currValue = 10.2f; codeint newCurrValue = (int)currValue; I just assuming they have the same logic?Deepfry
That's because you're just explicitly casting between to value types. However when you create a box of a value type you first have to unbox it to the underlying type.Sit
@Deepfry because there are no objects involved in this case - there is no boxed native type to unbox.Technician
@xanatos Last line returns (T)currentValueKorikorie
It is very strange that the function changes original type by the default value type, likely to cause run time errorOutrider
@Sit Thanks for the info. Any suggestion to improved the above code? I'm just assuming that my function above is the same with the code in my comment. :)Deepfry
It's actually a bad idea to have the same method try to do two things - return a default value and convert types. How do you intend to use it? Why not just use ?? ? Do you have a DataTable that uses strings instead of numeric types?Technician
@PanagiotisKanavos This is how I use the method. You also have a point changing the property to Nullable. _defaultMinValue = PFDMSDataCollection.ZeroNull<double>(datarow["dblDefaultMinValue"], 0.0); _defaultMaxValue = PFDMSDataCollection.ZeroNull<double>(datarow["dblDefaultMaxValue"], 0.0);Deepfry
R
9

You could try by using the IConvertible Interface, so it will at least work for types that implement it. Beware, this can still throw exceptions for types which do not make use of it, but for your conversions it's doing just fine:

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));
}

Concerning your cast to int from float: you are trying to convert a boxed type - it was boxed when you called your method which effectively converted it to an object. Boxed types can only be cast back to themselves. Since a cast to int is not the same type, it will not work. To reproduce without generics try this, it will also throw an InvalidCastException:

float currValue = 20.1f;

object yourValue = currValue;
int i = (int) yourValue;  //throws as well
Rink answered 22/5, 2015 at 6:59 Comment(1)
Thanks for your suggestion. I have tried it and works fine on my current requirement. I'll stick on your suggestion until such time I encounter another exception again. :)Deepfry
L
0

The issue you are experiencing is that you cannot cast String to int, which is what you're trying to do by casting currValue to T when T is of Type int.

To perform such an operation you would have to use Convert.ToInt32 or Int.Parse. either of which would undermine your current design.

Litigious answered 22/5, 2015 at 6:54 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.