Object of type 'System.Int16' cannot be converted to type 'System.Nullable`1[System.Int32]
Asked Answered
N

4

6

I've a method that generates list of class type from data of data reader.

if (datareader != null && datareader .HasRows)
{
  Dictionary<string, PropertyInfo> pDict= GetPropertyDictionary<T>();
  var fields = GetFieldNames(datareader );
  while (datareader .Read())
  {
    T myobj= new T();
    for (int index = 0; index < fields.Count; index++)
    {                        
      if (pDict.TryGetValue(fields[index], out PropertyInfo info))
      {
        var val1 = datareader .GetValue(index);                                
        info.SetValue(myobj, (val1 == DBNull.Value) ? null : val1, null);
      }
    }
  }
}

I have class properties, some of them are nullable.

public string StudentName{ get; set; }
public decimal? percentage{ get; set; }
public int? StudentNumber{ get; set; }

Code works properly for all properties except StudentNumber which is int.

In above code following line throws exeption Object of type 'System.Int16' cannot be converted to type 'System.Nullable`1[System.Int32] :

info.SetValue(myobj, (val1 == DBNull.Value) ? null : val1, null);

What can be done to solve this issue?

Nikaniki answered 13/6, 2018 at 16:38 Comment(5)
Does (val1 == DBNull.Value) ? null : (int?)val1 work as your ternary? val1's type is Int16 and not nullable, so it doesn't match the type expectation set by returning null in the first expression.Flatting
Yes its ternary. I am facing this issue only when type is int?, otherwise its working with decimal?, datetime?.Nikaniki
Possible duplicate of Conditional operator assignment with Nullable<value> types?Telex
@Priya: How did you solve this issue? All types use the same method in my case as wellTails
Hello @user2782405. It was issue with datatype. Since I am using reflection here, I need to specify the same datatype that is reader is returning from database. In database it was smallint and I was trying to convert it in int. so there it was failing.Nikaniki
M
4

I don't agree with this code for many reasons but to solve your current problem and answer your question it's because you can't explicitly convert Int16 to Int32 nor to Nullable<Int32> or int?.

To make this happen you need to first convert the value to Int32 then to Nullable<Int3>.

There are better ways but to make it clear what's going on and to fix this one error here you go...

info.SetValue(myobj, val1 == DBNull.Value ? null : (int?)Convert.ToInt32(val1), null);
Marlin answered 13/6, 2018 at 17:16 Comment(4)
but I can not directly use (int?) to convert it into Integer. This method is being commonly used for all types like string, int, decimal, date, double etc. I am facing issue only with int.Nikaniki
This is exactly why I don't agree with this code. It's not usable in a variety of ways but the answer was just to clarify your problem and fix that error. I believe what you need, IMO, is to back up and rethink the process a little and I mean this friendly I promise. I don't doubt your skills so don't take it as a blow. I just feel that what you want to do and what you're doing isn't inline with each other. This code assumes too much and doesn't consider the generic behavior you've intended. You're doing good though, please don't read this in disgust, I just answered the specific questionMarlin
@Michale, no no I will not take your suggestion in negative way. I will surely rethink over the taken approach to make it more efficient. :)Nikaniki
Thanks man. I certainly mean the best and I'm glad you're not upset.Marlin
F
4

The problem that you're having here is that, while you can cast a short to an int, you can't cast a boxed short to an int directly. ie,

object box = (short)5;
var x = (int?)box; // Invalid cast.
var y = (int?)(short?)box; // fine, we cast to short and then to int.

You could change the property type of your class to short?, or you could check if your property's type is Nullable<int32> and use Convert.ToInt32 on the value under that situation.

Flatting answered 13/6, 2018 at 17:22 Comment(5)
Can you suggest any generic solution? Because this method is called and executed for each and every column in datareaderNikaniki
@Nikaniki I can't think of a good generic approach to this. You're going to have to write some type-specifc code to handle type-specific conversion.Flatting
One strange thing I tried and it worked. Instead of simple int?, if I use Int16?, i.e. public Int16? StudentNumber { get; set; } , it works without exception. Why so!Nikaniki
@Nikaniki For the reasons I outlined above. You can cast from a boxed Int16 to Int16?. You cannot cast from a boxed Int16 to Int32 or Int32?, and will have to use a Convert.ToInt32 call.Flatting
Okay, okay! Thanks for explaining this! :) I will have to make some changes in my code then.Nikaniki
T
1

Try to change type:

var val1 = datareader.GetValue(index);    
var convertedValue = (val1 == DBNull.Value) ? null : Convert.ChangeType(val1, info.PropertyType);                            
info.SetValue(myobj, convertedValue, null);
Tombstone answered 13/6, 2018 at 16:43 Comment(2)
It gives another error :System.InvalidCastException: 'Invalid cast from 'System.Int16' to 'System.Nullable`1[[System.Int32,...]]Nikaniki
System.InvalidCastException: 'Invalid cast from 'System.Int16' to 'System.Nullable`1[[System.Int32, ]]Nikaniki
S
0

This error can occur when different types are given, check the field types of your database and your model file for that table.

Sinful answered 17/2, 2023 at 12:21 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.