考虑以下代码:
void Handler(object o, EventArgs e)
{
// I swear o is a string
string s = (string)o; // 1
//-OR-
string s = o as string; // 2
// -OR-
string s = o.ToString(); // 3
}
三种类型的施法有什么区别(好吧,第三种不是施法,但你明白了意图)。应该首选哪一种?
考虑以下代码:
void Handler(object o, EventArgs e)
{
// I swear o is a string
string s = (string)o; // 1
//-OR-
string s = o as string; // 2
// -OR-
string s = o.ToString(); // 3
}
三种类型的施法有什么区别(好吧,第三种不是施法,但你明白了意图)。应该首选哪一种?
当前回答
我想提请注意as操作员的以下细节:
https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/as
注意,as运算符仅执行参考转换,可空转换和装箱转换。as运算符不能执行其他转换,例如用户定义的转换应改为使用强制转换表达式来执行。
其他回答
string s = (string)o; // 1
如果o不是字符串,则引发InvalidCastException。否则,将o赋给s,即使o为空。
string s = o as string; // 2
如果o不是字符串或o为空,则将null赋给s。因此,不能将其用于值类型(在这种情况下,运算符永远不会返回null)。否则,将o指定给s。
string s = o.ToString(); // 3
如果o为空,则导致NullReferenceException。无论o是什么类型,都将任何o赋值给ToString()返回的值。
大多数转换都使用1-它简单明了。我倾向于几乎从不使用2,因为如果某个东西不是正确的类型,我通常会发生异常。我只看到这种返回null类型的功能需要设计糟糕的库,这些库使用错误代码(例如,返回null=error,而不是使用异常)。
3不是强制转换,只是方法调用。当您需要非字符串对象的字符串表示时,请使用它。
“as”基于“is”,这是一个关键字,用于在运行时检查对象是否与polimorphyly兼容(基本上,如果可以进行强制转换),如果检查失败,则返回null。
这两者是等价的:
使用“as”:
string s = o as string;
使用“is”:
if(o is string)
s = o;
else
s = null;
相反,c样式转换也在运行时进行,但如果无法进行转换,则会引发异常。
只是为了补充一个重要的事实:
“as”关键字仅适用于引用类型。您不能执行以下操作:
// I swear i is an int
int number = i as int;
在这种情况下,你必须使用铸造。
2可用于转换为派生类型。
假设a是动物:
b = a as Badger;
c = a as Cow;
if (b != null)
b.EatSnails();
else if (c != null)
c.EatGrass();
将得到最少的投喂。
如果我可以补充一下,所有给出的答案都很好:要直接使用字符串的方法和财产(例如ToLower),您不能编写:
(string)o.ToLower(); // won't compile
你只能写:
((string)o).ToLower();
但你可以写:
(o as string).ToLower();
as选项更可读(至少在我看来)。
“(string)o”将导致InvalidCastException,因为没有直接强制转换。
“o as string”将导致s为空引用,而不是引发异常。
“o.ToString()”本身并不是任何类型的强制转换,它是一个由对象实现的方法,因此以某种方式由.net中的每个类实现,这些类对它所调用的类的实例“做一些事情”并返回字符串。
不要忘记,对于转换为字符串,还有Convert.ToString(someType instanceOfThatType),其中someType是一组类型之一,本质上是框架基类型。