Casting object to int throws InvalidCastException in C# - c#

I have this method:
private static Dossier PrepareDossier(List<List<object>> rawDossier)
{
return new Dossier((int)rawDossier[0][0]);
}
When I use it I get an InvalidCastException. However, when I use Convert.ToInt32(rawDossier[0][0]) it works just fine. What is the problem?

The problem is that you don't cast an object to an int, you're attempting to unbox an int.
The object really has to be an int. It cannot be just anything that can be converted to an int.
So the difference is that this:
int a = (int)obj;
Really needs obj to be a boxed int, nothing else, whereas this:
int a = Convert.ToInt32(obj);
Will execute the ToInt32 method which will try to figure out what is really going on and do the right thing.
The "right thing" here is to ensure the object in question implements IConvertible and calling IConvertible.ToInt32, as is evident from the reference source:
public static int ToInt32(object value) {
return value == null? 0: ((IConvertible)value).ToInt32(null);
}
You can see the unboxing on try roslyn:
IL_0007: unbox.any [mscorlib]System.Int32
Conclusion: The object you're trying to unbox is not an int, but it is something that can be converted to an int.

I would guess this is because the object in your list is not an int.
Convert.ToInt32 will convert other non-int types so works.
Check what is being passed in to the method.

When you try to unbox int from an object, the boxed value should be int, otherwise you will receive an exception, while Convert.ToInt32 uses IConvertible implementation of boxed type to convert the value to int.
For example if the value which is boxed is string "100", unboxing it will throw an exception but using Convert.ToInt32, internally uses int.Parse.
Boxing and Unboxing (C# Programming Guide)
Attempting to unbox a reference to an incompatible value type causes
an InvalidCastException.

Related

Invalid Cast Exception While converting from smallint to Int32?

The code below fills the properties of my model from the DataReader.I made some properties Nullable and it isn't working since then.
foreach (var property in _properties)
{
property.SetValue(model, null, null);
if (columnsInDataReader.Contains(property.Name.ToLower()))
{
if (!(_dataReader[property.Name] == DBNull.Value))
property.SetValue(model, _dataReader[property.Name]);
}
}
The property is Int32? and the database column is smallint and the conversion fails.
Even if an implicit conversion from short to int? do exists, the issue here arises from the fact that the data reader returns a boxed short, for which you need an unboxing conversion. In this specific case, the conversion is from object to a value type (int?).
The paragraph that matches your situation is the last of the cited section: since the object returned is a boxed short and not a boxed int, the cast fails.
As a concrete example, compare these two snippets:
short src = 42;
int? dst = (int?)src;
object src = (short)42;
int? dst = (int?)src;
While the first one succeeds, the second throws an InvalidCastException.
In your case, no explicit cast occurs, however the call to SetValue applies similar conversion rules, and therefore fails.
Summing up, in order to have the call succeed, you must choose the type of the property among those that are castable at runtime from the type of the extracted object, such as short and short?.

Can I cast an integer to a long when the types are generic/boxed?

The method below looks for a particular key in a dictionary and attempts to safely store it in destination if it can. The problem I am running into is when T=Int64 and the item in the dictionary is Int32 or UInt32 (both of which can fit inside an Int64 without data loss). valueAsObject is T returns false when T is Int64 and valueAsObject is Int32.
Is it possible to safely cast valueAsObject to T without just trying it and catching any exceptions? I would like to avoid exceptions, though if that is the only way I can make it work.
public static void MyMethod<T>(IDictionary<String, Object> dictionary, String key, ref T destination)
{
if (!dictionary.ContainsKey(key))
return;
var valueAsObject = dictionary[key];
if (!(valueAsObject is T))
return;
destination = (T)valueAsObject;
}
Basically, I want the function to do nothing (return) if the thing found in the dictionary can not be safely stored in a type T variable (without data loss), otherwise it should cast it as necessary and store it.
This is not built-in at the language or runtime level. You can use Convert.ChangeType to perform the conversion. This method also performs lossy conversions so you probably have to build your own conversion logic (which will involve casts and be ugly).
You can't just do something like this?
public static void MyMethod<T>( IDictionary<string,object> dictionary , string key , ref T destination )
{
object value ;
bool found = dictionary.TryGetValue( key , out value ) ;
if (found && value is T)
{
destination = (T) value ;
}
return;
}
The is operator:
evaluates to true if the provided expression is non-null, and the provided object
can be cast to the provided type without causing an exception to be thrown.
.
.
.
Note that the is operator only considers reference conversions, boxing conversions,
and unboxing conversions. Other conversions, such as user-defined conversions, are not considered.
Basically, if the object directly inherits from the specified type, or implements the type (if T is an interface), is should return true and you should be able to down-cast the object to your type T.
If, however, you need to worry about user-defined conversion operators, you'll need to reflect over the object's type and over typeof(T) to see if a user-defined conversion operator is defined on either type that will convert the object to a compatible type. Getting that right is likely to be...tricky.
This is the final solution I went with. It came from a number of comments and other answers so I encourage reading the other answers/comments for additional details as to why this was necessary:
private static void GetFromDictionary<T>(IDictionary<String, Object> dictionary, String key, ref T outputLocation)
{
if (!dictionary.ContainsKey(key))
return;
var valueAsObject = dictionary[key];
if (!CanBeCastTo<T>(valueAsObject))
return;
outputLocation = (T)Convert.ChangeType(valueAsObject, typeof(T));
}
private static bool CanBeCastTo<T>(Object thingToCast)
{
if (thingToCast is T)
return true;
var tType = typeof(T);
if (tType == typeof(Int64) && thingToCast is Int32)
return true;
if (tType == typeof(Double) && thingToCast is Decimal)
return true;
return false;
}
In my case, I only needed to handle a certain subset of primitive types (Int32, Int64, String, Double, Decimal) and I was willing to accept lossy conversion of Decimal to Double.
The take away here is that the "is" operator will return false for primitives even if it can fit without loss (Int32 in Int64). Also, (T)valueAsObject will not do an explicit typecast. So if valueAsObject is of type Int32 and T is of type Int64 the above will throw an exception even though (Int64)valueAsObject is valid. This one bit me but luckily #usr suggested using Convert.ChangeType which handles the problem.
Optimizations could be made to the above code but I chose to leave it as is for readability.

Does a ValueType get boxed when is declared as part of a class?

Considering this class:
public class Foo
{
public Int32 MyField;
}
I guess the "MyField" member is not on the thread stack because as it could be accessed by several threads, it has to be definitely in the managed heap, but does it means it is boxed and unboxed everytime it is used?
Thanks in advance
No, it is not boxed every time it is used. Boxing only occurs when you are coercing a value type into a reference type - it really has nothing to do with where the actual memory for the value was allocated (or even if any memory was allocated).
In your case, it's how you act on MyField that will determine if it's boxed, not how Foo is treated.
//No Boxing
var f = new Foo();
f.MyField = 5;
int val = f.MyField;
//Boxing
var f = new Foo();
f.MyFIeld = 5;
object val = f.MyField;
Note that in the second example val now contains a reference to a boxed int. MyField is still (and will always remain) an unboxed int and can be accessed without unboxing (thanks for pointing out the needed clarification, LukeH)
No, the value type is not boxed.
Boxing only occurs when you use a value type as though it is an object, for example when storing an int in an array of object. That is:
object[] a = new object[10];
int x = 1;
a[0] = x;
In that case, the value type is boxed.
But a value type stored as a field inside a class is not boxed.
No, boxing only occurs when a value type is treated as a System.Object (usually by implicit casting, i.e. passing it as a method parameter)
Value types only get boxed when they're assigned to a reference type variable (e.g. object). If you never assign MyField to anything other than an int or another struct to which it can be cast (e.g. double), it won't ever be boxed.

C# value type casting: how it works? [duplicate]

This question already has an answer here:
Closed 12 years ago.
Possible Duplicate:
Why does this conversion doesn't work?
Hi,
i discovered a strange behaviour of the framework.
This code throws an exception:
byte a = 1;
object b = a;
Console.WriteLine(b.GetType());
Console.WriteLine((byte)b);
Console.WriteLine((int)(byte)b);
Console.WriteLine(Convert.ToInt32(b));
Console.WriteLine((int)b);
The last line throws a System.InvalidCastException.
I'd like to know what are the mechanism in the framework that make this code illegal.
Is it a problem of boxing/unboxing?!
Yes, boxed value types can only be unboxed to the exact same type.
The variable b is a boxed byte.
When you do (int)(byte)b you're unboxing b back to a byte and then converting that unboxed byte to an int.
When you do (int)b you're attempting to unbox b directly to an int, which is illegal.
Edit...
As Jon mentions in his answer, there are cases where you don't have to unbox to the exact same type. Specifically:
A boxed T can be unboxed to Nullable<T>.
A boxed Nullable<T> can be unboxed to T, assuming that the nullable isn't actually null.
A boxed enum with an underlying type of T can be unboxed to T.
A boxed T can be unboxed to an enum with an underlying type of T.
Eric Lippert has a blog post on this.
Why? Because a boxed T can only be
unboxed to T.
Or Nullable< T >.
When you unbox, it has to be to one of the following:
The exact same type
The nullable form of the exact same type
If it's an enum type value, then you can unbox to the underlying type
If it's an integral type value, you can unbox to an enum which uses that underlying type
Examples:
using System;
class Test
{
enum Foo : short
{
Bar = 1
}
static void Main()
{
short x = 1;
object o = x;
short a = (short) o;
short? b = (short?) o;
Foo c = (Foo) o;
o = Foo.Bar;
short d = (short) o;
}
}
Anything else will give an exception. In particular, you can't unbox to a different type even if there's an implicit conversion from the actual type to your target type, which is what you're trying to do on the last line of your example.
You also can't unbox from an integral value to a nullable form of an enum with the same underlying type (or the reverse situation).
Note that if you box a nullable value type value, the result is either null (if the original value was the null value for the type) or the boxed non-nullable value... there's no such thing as a "boxed nullable value type" if you see what I mean.
Is it a problem of boxing/unboxing?
Yes. bis a boxed byte. So you need to unbox it to a byte first , like in (int)(byte)b

Different Cast Types in C# [duplicate]

This question already has answers here:
Closed 13 years ago.
Possible Duplicates:
Casting: (NewType) vs. Object as NewType
Why is the C# “as” operator so popular?
Hey,
I know this may be a silly question but this doubt came to me today.
What is the difference between doing
String text = (String) variable;
and
String text = variable as String;
?
A cast can do three things:
Perform a user-defined conversion
Perform an unboxing conversion
Perform a reference conversion
An as operation is almost always a reference conversion, the only exception being unboxing to a nullable type:
object x = "hello";
int? y = x as int?; // y is null afterwards
Then there's the behaviour with conversions which fail at execution time. So the differences are:
Casts performing reference conversions or unboxing will throw InvalidCastException on failure; as will result in the null value of the target type instead
Casts can perform user-defined conversions; as can't
Casts can unbox to non-nullable value types; as can only be used for unboxing if the target type is a nullable value type
as will return null if variable isn't actually of that type (String in this case). The cast will throw an exception.
Here is the link to Eric Lippert's blog on casting in C#. I'd summarize it, but it's pretty short and he'll explain it much better than me.
http://blogs.msdn.com/ericlippert/archive/2009/10/08/what-s-the-difference-between-as-and-cast-operators.aspx
And here is his post on the cast operator:
http://blogs.msdn.com/ericlippert/archive/2009/03/19/representation-and-identity.aspx
There are a lot of different ways to cast in C#.
This will try to cast the reference to a String reference. If the cast fails, it throws an exception:
string text = (String) variable;
This will try to cast the reference to a String reference. If the cast fails, it will return a null reference to be assigned to the variable:
string text = varible as String;
This will cast a string reference to an object reference, which is a safe casting as String inherits from Object:
object text = (object)"1337";
Casting to a parent class can also be done implicitly:
object text = "1337";
This will box a value inside an object, then unbox it to a plain value again:
int value = 42;
object boxed = (object)value;
int valueAgain = (int)boxed;
The boxing can also be done implicitly:
int value = 42;
object boxed = value;
int valueAgain = (int)boxed;
This will make a widening conversion from byte to int:
byte a = 42;
int b = (int)a;
The same works as an implicit conversion:
byte a = 42;
int b = a;
This will make a narrowing conversion from int to byte, throwing away the overflow:
int a = 512;
byte b = (byte)a; // b now contains 0

Categories

Resources