Reputation: 2925
I try to extend the DataRow object with this generic method :
public static T? Get<T>(this DataRow row, string field) where T : struct
{
if (row.IsNull(field))
return default(T);
else
return (T)row[field];
}
It's work fine when T is int
, decimal
, double
, etc.
But when I try to use with string, I have this error :
"The type 'string' must be a non-nullable value type in order to use it as parameter 'T' in the generic type or method 'System.Nullable'"
How can I correct this ?
I know that string is not a struct but I wan't to return null if the string field is DBNull.
Upvotes: 4
Views: 5627
Reputation: 9870
Unfortunately, you're not going to be able to get the Nullable return type AND support for reference types by using generics, unless you specify that you want a Nullable returned when you make the call
public static T Get<T>(this DataRow row, string field)
{
if (row.IsNull(field))
return default(T);
else
return (T)row[field];
}
and when you call
var id = dr.Get<int?>("user_id");
I didn't test this, just tossed it up here. Give it a shot.
EDIT:
Alternatively, if you really wanted to convert the value types into nullables and still be able to support reference types something like this might work
public static object GetDr<T>(this DataRow row, string field)
{
// might want to throw some type checking to make
// sure row[field] is the same type as T
if (typeof(T).IsValueType)
{
Type nullableType = typeof(Nullable<>).MakeGenericType(typeof(T));
if (row.IsNull(field))
return Activator.CreateInstance(nullableType);
else
return Activator.CreateInstance(nullableType, new[] { row[field] });
}
else
{
return row[field];
}
}
However, it'd require a cast on every usage
var id = dr.Get<string>("username") as string;
var id = (int?)dr.Get<int>("user_id");
This is, however, not going to be nearly as efficient as just accepting the nullable type in the generic type parameters.
Upvotes: 2
Reputation: 9861
I think that this is what you want:
public static T? GetValue<T>(this DataRow row, string field) where T : struct
{
if (row.IsNull(field))
return new T?();
else
return (T?)row[field];
}
public static T GetReference<T>(this DataRow row, string field) where T : class
{
if (row.IsNull(field))
return default(T);
else
return (T)row[field];
}
Upvotes: 6
Reputation: 101142
string
is not a struct
, but a class
. That is what the error message tells you. Just remove the constraint.
Maybe you want to have a look at the DataRowExtensions.
Upvotes: 5
Reputation: 231
ds.Tables[7].Rows.OfType<DataRow>().ToList().ForEach(f => tempList.Add(new MyEntity
{
Id = int.Parse(f.ItemArray[0].ToString()),
Title = f.ItemArray[1].ToString()
}));
Upvotes: 2
Reputation: 269578
How about something like this? Not quite the same as your example, but pretty usable for reference-types, nullable value-types and non-nullable value-types alike:
int v = row.Get<int>("vvv"); // throws if column is null
int? w = row.Get<int?>("www"); // set to null if column is null
int x = row.Get<int?>("xxx") ?? -1; // set to -1 if column is null
string y = row.Get<string>("yyy"); // set to null if column is null
string z = row.Get<string>("zzz") ?? "" // set to "" if column is null
// ...
public static T Get<T>(this DataRow source, string columnName)
{
if (source == null)
throw new ArgumentNullException("source");
if (columnName == null)
throw new ArgumentNullException("columnName");
if (columnName.Length < 1)
throw new ArgumentException("Name cannot be empty.", "columnName");
if (source.IsNull(columnName))
{
T defaultValue = default(T);
if (defaultValue == null)
return defaultValue;
}
// throws if the column is null and T is a non-nullable value type
return (T)source[columnName];
}
Upvotes: 1
Reputation: 564771
You have an explicit condition that prevents this from working with string:
where T : struct
System.String is a class, not a struct. If your goal is to handle value types and string, I would make a separate method for string, and leave this alone for your other types.
Upvotes: 2
Reputation: 22859
As Wes points out, your issue is the constraint to struct. I'd expect that extension method to work without constraints...
Ah, I see now, you're returning T?
Well, I am not sure but can you define two variants of the method one constraining to struct
, the other to class
and returning T
?
Upvotes: 1