考虑以下代码:

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
}

三种类型的施法有什么区别(好吧,第三种不是施法,但你明白了意图)。应该首选哪一种?


当前回答

这真的取决于你是否知道o是否是一个字符串,以及你想用它做什么。如果你的评论意味着o真的是一个串,我更喜欢直接(字符串)o转换-它不太可能失败。

使用直接转换的最大优点是,当它失败时,您会得到一个InvalidCastException,它会告诉您发生了什么错误。

使用as运算符,如果o不是字符串,那么s将设置为null,这在您不确定并想测试s时很方便:

string s = o as string;
if ( s == null )
{
    // well that's not good!
    gotoPlanB();
}

但是,如果不执行该测试,则稍后将使用s并引发NullReferenceException。一旦它们在野外发生,它们往往更常见,也更难追踪,因为几乎每一行都会取消引用一个变量,并可能抛出一个变量。另一方面,如果您试图转换为值类型(任何基元,或DateTime等结构),则必须使用直接转换-as无法工作。

在转换为字符串的特殊情况下,每个对象都有一个ToString,因此如果o不为空,并且您认为ToString方法可以执行您想要的操作,则第三个方法可能是正确的。

其他回答

“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;

在这种情况下,你必须使用铸造。

使用直接转换字符串s=(string)o;如果在应用程序的逻辑上下文中,字符串是唯一有效的类型。使用这种方法,您将获得InvalidCastException并实现快速失败的原则。您的逻辑将受到保护,不会进一步传递无效类型,或者如果用作运算符,将获得NullReferenceException。

如果逻辑需要几个不同的类型,则将字符串s=o转换为字符串;并检查null或use-is运算符。

C#7.0中出现了新的酷炫功能,以简化转换,并检查模式匹配:

if(o is string s)
{
  // Use string variable s
}

or

switch (o)
{
  case int i:
     // Use int variable i
     break;
  case string s:
     // Use string variable s
     break;
 }

如果我可以补充一下,所有给出的答案都很好:要直接使用字符串的方法和财产(例如ToLower),您不能编写:

(string)o.ToLower(); // won't compile

你只能写:

((string)o).ToLower();

但你可以写:

(o as string).ToLower();

as选项更可读(至少在我看来)。

这真的取决于你是否知道o是否是一个字符串,以及你想用它做什么。如果你的评论意味着o真的是一个串,我更喜欢直接(字符串)o转换-它不太可能失败。

使用直接转换的最大优点是,当它失败时,您会得到一个InvalidCastException,它会告诉您发生了什么错误。

使用as运算符,如果o不是字符串,那么s将设置为null,这在您不确定并想测试s时很方便:

string s = o as string;
if ( s == null )
{
    // well that's not good!
    gotoPlanB();
}

但是,如果不执行该测试,则稍后将使用s并引发NullReferenceException。一旦它们在野外发生,它们往往更常见,也更难追踪,因为几乎每一行都会取消引用一个变量,并可能抛出一个变量。另一方面,如果您试图转换为值类型(任何基元,或DateTime等结构),则必须使用直接转换-as无法工作。

在转换为字符串的特殊情况下,每个对象都有一个ToString,因此如果o不为空,并且您认为ToString方法可以执行您想要的操作,则第三个方法可能是正确的。

当您使用FindControl方法时,as关键字在asp.net中很好。

Hyperlink link = this.FindControl("linkid") as Hyperlink;
if (link != null)
{
     ...
}

这意味着您可以对类型化变量进行操作,而不必像直接转换那样从对象转换它:

object linkObj = this.FindControl("linkid");
if (link != null)
{
     Hyperlink link = (Hyperlink)linkObj;
}

这不是一件大事,但它节省了代码行和变量赋值,而且可读性更强