I’ve written a piece of code for converting a DataTable
object(which is created from an uploaded excel) to a list
of custom object(ExcelTemplateRow
in my case). While this method works fine when the values are supplied as expected(in terms of data type of the corresponding column), the code breaks and throws the below error when I try to give a random value(and hence the data type changes):
Object of type 'System.String' cannot be converted to type 'System.Nullable`1[System.Double]'
Below is the method for converting DataTable
object to list:
public static List<T> ConvertToList<T>(DataTable dt)
{
var columnNames = dt.Columns.Cast<DataColumn>().Select(c => c.ColumnName.ToLower()).ToList();
var trimmedColumnNames = new List<string>();
foreach (var columnName in columnNames)
{
trimmedColumnNames.Add(columnName.Trim().ToLower());
}
var properties = typeof(T).GetProperties();
return dt.AsEnumerable().Select(row => {
var objT = Activator.CreateInstance<T>();
foreach (var property in properties)
{
if (trimmedColumnNames.Contains(property.Name.Trim().ToLower()))
{
try
{
if(row[property.Name] != DBNull.Value)
{
property.SetValue(objT, row[property.Name]);
}
else
{
property.SetValue(objT, null);
}
}
catch (Exception ex)
{
throw ex;
}
}
}
return objT;
}).ToList();
}
My custom object looks somewhat like this:
public class ExcelTemplateRow
{
public string? Country {get; set;}
public double? Year {get; set;}
//....
//....
}
In the excel that I’m uploading, for the Year
field, the code works fine when I give proper double values viz 2020, 2021, 2022
etc. but the code breaks when I give something wrong e.g 2023g
. It then assumes I’m passing a string and hence the error. I tried by changing the declaration of the Year
property to public object? Year {get; set;}
but it doesn’t help. I want to make the method robust enough to handle such scenarios. Any help and I’d be highly grateful.
2
Answers
There’s a few things to consider here, but I’ll try to be as terse as possible. When you say:
This means the C# type system is working exactly as intended. A double should never be able to accept the value of "2023g". You probably want to store the year as a string instead. This may involve an intermediate stage of validation, where you import all of your data as a string (ExcelTemplateRow should all be strings in this case).
Then your work is ahead of you to validate the data, and then once you’ve handled any errors, only then can you think about using types such as Double?. Although, you probably don’t want to store your year as a double, an int might be more appropriate. Or maybe it isn’t; perhaps you want to store the errors, because that’s what a user has entered. Some careful consideration is required here. Don’t rush with the type system, let it work for you, thinking about which datatypes to use will help you design the rest of your code.
The issue here is the data coming from the excel, not your code who behave correctly.
Say you try using the
T is double?
then youdouble.tryParse(row)
and when it fails you take the 4 first caracter of the string2023g
but what will happen if you have another property of typedouble?
but expect only 2 or 3 numbers but the user put some dummy stuff how do you will manage that ? It’s impossible.Fix the Excel not your code 😉
Log the error, send a message to the user to fix the data 🙂