如何(有效地)将SqlDataReader字段转换(转换)为其对应的c#类型? [英] How to (efficiently) convert (cast?) a SqlDataReader field to its corresponding c# type?
问题描述
让我们看一个例子:
命名空间测试
{
使用System;
using System.Data;
using System.Data.SqlClient;
public enum MyEnum
{
FirstValue = 1,
SecondValue = 2
}
public class MyObject
{
private String field_a;
private Byte field_b;
private MyEnum field_c;
public MyObject(Int32 object_id)
{
using(SqlConnection connection = new SqlConnection(connection_string))
{
connection.Open ;
using(SqlCommand command = connection.CreateCommand())
{
command.CommandText =sql_query;
使用(SqlDataReader reader = command.ExecuteReader(CommandBehavior.SingleRow))
{
reader.Read();
this.field_a = reader [field_a];
this.field_b = reader [field_b];
this.field_c = reader [field_c];
}
}
}
}
}
}
这显然是失败的,因为三个 this.field_x = reader [field_x];
调用抛出不能将类型object隐式转换为xxx。显示转换存在(是否缺少转换?)
编译器错误。
知道两种方法(让我们使用 field_b
示例):第一个是 this.field_b =(Byte)reader [field_b]; code>,第二个是
this.field_b = Convert.ToByte(reader [field_b]);
。
选项号1的问题是 DBNull
字段抛出异常,因为转换失败(即使是可空类型 String
),ant第二个问题是它不保留空值(
Convert.ToString(DBNull)
产生一个 String 。
因此,在互联网上的几次查找后,在这里StackOverflow,我想出了:
public static class实用程序
{
public static T FromDatabase ; T>(Object value)其中T:IConvertible
{
if(typeof(T).IsEnum == false)
{
if(value == null || Convert.IsDBNull(value)== true)
{
return default(T);
}
else
{
return(T)Convert.ChangeType(value,typeof(T));
}
}
else
{
if(Enum.IsDefined(typeof(T),value)== false)
{
throw new ArgumentOutOfRangeException();
}
return(T)Enum.ToObject(typeof(T),value);
}
}
}
问题是:我错过了什么?我在做一个WOMBAT(浪费金钱,大脑和时间),因为有一个更快,更干净的方式做到吗?这是正确的吗?利润?
如果字段允许空值,请不要使用常规基本类型。使用 C#可空的
类型和 为
keyword 。
int? field_a = reader [field_a] as int?
string field_b = reader [field_a] as string;
将?
添加到任何不可为空C#类型使它可空。使用作为
关键字将尝试将对象转换为指定的类型。如果转换失败(类似于 DBNull
),则操作符返回 null
。
注意:使用作为
的另一个小好处是它比正常投放稍快。因为它也可以有一些缺点,如使你更难跟踪错误,如果你尝试转换为错误的类型,这不应该被认为是总是使用作为
超过传统铸造。正规铸造已经是一个相当便宜的操作。
First, let me explain the current situation: I'm reading records from a database and putting them in an object for later use; today a question about the database type to C# type conversion (casting?) arose.
Let's see an example:
namespace Test
{
using System;
using System.Data;
using System.Data.SqlClient;
public enum MyEnum
{
FirstValue = 1,
SecondValue = 2
}
public class MyObject
{
private String field_a;
private Byte field_b;
private MyEnum field_c;
public MyObject(Int32 object_id)
{
using (SqlConnection connection = new SqlConnection("connection_string"))
{
connection.Open();
using (SqlCommand command = connection.CreateCommand())
{
command.CommandText = "sql_query";
using (SqlDataReader reader = command.ExecuteReader(CommandBehavior.SingleRow))
{
reader.Read();
this.field_a = reader["field_a"];
this.field_b = reader["field_b"];
this.field_c = reader["field_c"];
}
}
}
}
}
}
This is (obviously) failing because the three this.field_x = reader["field_x"];
calls are throwing the Cannot implicitly convert type 'object' to 'xxx'. An explicit conversion exists (are you missing a cast?).
compiler error.
To correct this I currently know of two ways (let's use the field_b
example): number one is this.field_b = (Byte) reader["field_b"];
and number two is this.field_b = Convert.ToByte(reader["field_b"]);
.
The problem with option number one is that DBNull
fields are throwing exceptions as the cast is failing (even with nullable types as String
), ant the problem with number two is that it's not preserving null values (the Convert.ToString(DBNull)
yields a String.Empty
), and I can't use them with enums too.
So, after a couple of lookups on the internet and here at StackOverflow, what I came up with is:
public static class Utilities
{
public static T FromDatabase<T>(Object value) where T: IConvertible
{
if (typeof(T).IsEnum == false)
{
if (value == null || Convert.IsDBNull(value) == true)
{
return default(T);
}
else
{
return (T) Convert.ChangeType(value, typeof(T));
}
}
else
{
if (Enum.IsDefined(typeof(T), value) == false)
{
throw new ArgumentOutOfRangeException();
}
return (T) Enum.ToObject(typeof(T), value);
}
}
}
This way I should handle every case.
Question is: Am I missing something? Am I doing a WOMBAT (Waste Of Money, Brain And Time) as there's a quicker and cleaner way to do it? It's all correct? Profit?
If a field allows nulls, don't use regular primitive types. Use the C# nullable
type and the as
keyword.
int? field_a = reader["field_a"] as int?;
string field_b = reader["field_a"] as string;
Adding a ?
to any non-nullable C# type makes it "nullable". Using the as
keyword will attempt to cast an object to the specified type. If the cast fails (like it would if the type is DBNull
), then the operator returns null
.
Note: Another small benefit of using as
is that it is slightly faster than normal casting. Since it can also have some downsides, such as making it harder to track bugs if you try to cast as the wrong type, this shouldn't be considered a reason for always using as
over traditional casting. Regular casting is already a fairly cheap operation.
这篇关于如何(有效地)将SqlDataReader字段转换(转换)为其对应的c#类型?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!