sql = "SELECT Levels FROM VEmpLevel where id = '001'";
strReturn = cmd.ExecuteScalar(sql) as string;
执行sql语句在查询分析器中明明Levels有值为1,可是使用该方法返回结果却是null.
下面的同样报错:
sql = "select birthday from employee where id = '010001'";
using (SqlDataReader dr = db.GetDataReader(sql))
{
if(dr.Reader())
{
this._EmployeeBirthday = dr["birthday"] as string;
}
}
bithday字段明明有值,可是返回结果_EmployeeBirthday 还是null。
Solution:
经过测试发现原来是这样的原因 :as 运算符必须与引用类型一起使用(“int”是值类型,System.DateTime也是值类型。),所以像这种从数据库中读取字段的类型转换,因为可能不太清楚具体某个字段是什么类型的,这个时候最好使用Convert的静态转换方法比较安全。
Summarize:
那么,具体进行类型转换的操作中,应该遵循什么原则呢?
MSDN中关于as关键字的C# 参考:
用于在兼容的引用类型之间执行转换。例如:
string s = someObject as string;
if (s != null)
{
// someObject is a string.
}
备注:
as 运算符类似于强制转换,所不同的是,当转换失败时,运算符将产生空,而不是引发异常。更严格地说,这种形式的表达式 :
expression as type
等效于:
expression is type ? (type)expression : (type)null
只是 expression
只被计算一次。
注意,as 运算符只执行引用转换和装箱转换。as 运算符无法执行其他转换,如用户定义的转换,这类转换应使用 cast 表达式来执行。
// The as operator.
using System;
class Class1
{
}
class Class2
{
}
class MainClass
{
static void Main()
{
object[] objArray = new object[6];
objArray[0] = new Class1();
objArray[1] = new Class2();
objArray[2] = "hello";
objArray[3] = 123;
objArray[4] = 123.4;
objArray[5] = null;
for (int i = 0; i < objArray.Length; ++i)
{
string s = objArray[i] as string;
Console.Write("{0}:", i);
if (s != null)
{
Console.WriteLine("'" + s + "'");
}
else
{
Console.WriteLine("not a string");
}
}
}
}
输出:
0:not a string
1:not a string
2:'hello'
3:not a string
4:not a string
5:not a string
在程序中,进行类型转换是常见的事。那么在C#中支持以前语言的类型转换方法,即用类型名进行强行转换,例如:
object objTest = new NewType();
NewType newValue = (NewType)objTest;
但是这样转换,有个严重的问题,就是在把objTest强转换成NewType类型对象的时候,这个过程是不安全的,因此需要用try-catch语句来进行保护。这样一来,比较安全的代码方式应该如下所示。
object objTest = new NewType();
NewType newValue = null;
try
{
newValue = (NewType)objTest;
}
catch( Exception err )
{
MessageBox.Show( err.Message );
}
但是如上的写法在C#中已经属于过时的写法,而且也属于比较低效的写法。在C#中比较高效而且安全的写法,应该用as操作符,那么完成如上类似功能的正确代码应该如下。
object objTest = new NewType();
NewType newValue = objTest as NewType;
那么很明显,如上的写法首先看起来很简便,至少代码数量和强转方式一样。至于安全性,对于as操作符来说,它不会做过的转换操作,当需要转换对象的类型属于转换目标类型或者转换目标类型的派生类型的时候,那么此转换操作才能成功,而且并不产生新的对象。因此用as来进行类型转换使安全的。为什么用as操作符进行类型转换的效率要高于老式的类型转换的,因为用as操作符进行转换就如前面所说的,首先判断当前对象的类型,当类型满足要求后才进行转换。而传统的类型转换方式,是用当前对象直接去转换,而且为了保护转换成功,要加上try-catch,这就决定了它的效率不会高于as操作符的效率。
要注意的时候,不管用传统方式,还是用as操作符进行类型转换之后,在使用之前,需要进行判断转换是否成功,如下:
if( newValue!= null )
{
//Work with the object named "newValue"
}
但是,使用as操作符有如下几点限制。
第一个就是,不用在类型之间进行类型转化,即如下编写就会出现编译错误。
NewType newValue = new NewType();
NewType1 newValue = newValue as NewType1;
第二个就是,不能应用在值类型数据,即不能如下写(也会出现编译错误)。
object objTest = 11;
int nValue = objTest as int;
对于第一点所提的,可以用传统的类型转换方式来完成,但是光用如下的方式,是不能正确完成。
NewTypeOne newTestOne = new NewTypeOne();
NewTypeTwo newTestTwo = (NewTypeTwo)newTestOne;
但是光如上写是不能完成的,要想使如上的操作能正确完成,在原有类型中增加类型转换操作符函数,即需要完成类似如下的代码。
public class NewTypeOne
{
public static explicit operator NewTypeTwo( NewTypeOne objTest )
{
//Convert object into new type
}
}
对于第二点所提的,在C#中可以使用is操作符,再加上老式的类型转换操作,就可以安全完成转换,那么要完成如上操作,正确的写法如下。
object objTest = 11;
if( objTest is int )
{
int nValue = (int)objTest;
}
除了如上两点限制外,在用as操作符来进行类型转换的时候,有个细微的问题。在前面所说的,用as来进行类型转换的时候,所要转换的对象类型必须是目标类型或者转换目标类型的派生类型,那么这样就有个问题,即用as操作符来进行类型转换的时候无法转换成正确的类型,也就是说本来应该转换成子类型,却转换成了父类型。但是我并不认为这是个严重问题,因为在用as操作符来进行类型转换的时候,如何选择目标类型在编码的时候已经很明确了,即用父类型作为目标类型,那么类型转换的目的就是转换成父类型对象进行操作;反之亦然。
在C#中已经提供了一个很好的类型转换方式,那么在进行类型转换的时候,可以按照如下的方式进行选择。
类型转换 |
使用选择 |
Object => 已知引用类型 |
使用as操作符来完成 |
Object => 已知值类型 |
先使用is操作符来进行判断,再用类型强转方式进行转换 |
已知引用类型之间转换 |
首先需要相应类型提供转换函数,再用类型强转方式进行转换 |
已知值类型之间转换 |
最好使用系统提供的Convert类所涉及的静态方法 |