将对象转换为字符串:强制类型转换 vs toString方法,当对象本身就是字符串时应该如何处理?

80

这不是真正的问题,但是我很好奇。当我将一个字符串保存在一个DataRow中时,它会被强制转换为Object。当我想要使用它时,我必须将其转换为ToString。据我所知,有几种方法可以做到这一点,第一种方法是

string name = (string)DataRowObject["name"]; //valid since I know it's a string

还有另一个是:

string name = DataRowObject["name"].ToString();

我想知道它们之间的区别是什么?第一个更有效吗?(这只是我的猜测,在我的脑海中,ToString()方法是通过一些循环机制实现的,而仅仅将其转换为字符串“可能”更快,但这只是我内心的“直觉”)。

是否有更快/更优雅的方法来做到这一点?

有人能为我解决这个问题吗?


5
我知道你提到了Object是一个字符串,但如果你不确定返回的对象是否为null,你也可以使用"Convert.ToString(DataRowObject["name"]);"进行类型转换。这样做的好处是,如果对象为null,它会返回一个空字符串(string.empty),以避免任何空引用异常。 - n00b
9个回答

57
这两个方法的目的不同。任何对象的ToString方法都应该返回该对象的字符串表示形式。转换则完全不同,“as”关键字执行条件转换,正如已经说过的那样。“as”关键字基本上表示“如果该对象是此类型,则获取对该类型的引用”,而ToString则表示“获取该对象的字符串表示形式”。在某些情况下,结果可能相同,但两者绝不能视为可互换,因为它们存在于不同的目的中。如果您的意图是进行转换,则应始终使用转换,而不是ToString。
来自http://www.codeguru.com/forum/showthread.php?t=443873 另请参见http://bytes.com/groups/net-c/225365-tostring-string-cast

1
所以如果我理解正确的话。.ToString将始终返回对象的字符串。而强制转换将在无法返回字符串时失败? - Linda Lawton - DaImTo
1
@DaImTo: 当你将类型A的对象强制转换为类型B(如果强制转换成功),则会得到一个新对象,您可以再次将其强制转换回类型A。强制转换并没有改变它们本质上是什么(核心),而是改变了它们被看作是什么。在通常情况下,转换是单向的。它创建了一个新对象(仅)代表旧对象。例如:当将学生对象st转换为toString()时,将成为一个字符串,看起来像学生:@1343;43234。您认为您可以将其转换回具有字段值的学生吗? - Andiana
@Andiana,在C#参考考试书中,它说:“当创建自己的类型时,您可以重写ToString方法以返回对象的字符串表示形式。如果需要,您可以创建Parse和TryParse方法将字符串转换回原始对象。实现IFormattable接口是必需的,以便Convert类可以使用您的对象。”您能否根据您之前所说的内容来解释一下这个问题。谢谢 - Ashraf Alshahawy
string name = DataRowObject["name"] as String; 这样写可以吗?只是好奇... - Jack Griffin

32

如果您知道它是一个 String ,那么请将其转换为 String 。 将对象强制转换比调用虚方法更快。

编辑:以下是一些基准测试的结果:

============ Casting vs. virtual method ============
cast 29.884 1.00
tos  33.734 1.13

我使用了Jon Skeet的BenchmarkHelper,代码如下:

using System;
using BenchmarkHelper;

class Program
{
    static void Main()
    {
        Object input = "Foo";
        String output = "Foo";

        var results 
           = TestSuite.Create("Casting vs. virtual method", input, output)
            .Add(cast)
            .Add(tos)
            .RunTests()
            .ScaleByBest(ScalingMode.VaryDuration);

        results.Display(ResultColumns.NameAndDuration | ResultColumns.Score,
                results.FindBest());
    }

    static String cast(Object o)
    {
        return (String)o;
    }

    static String tos(Object o)
    {
        return o.ToString();
    }
}

看起来转换实际上比调用ToString()略快一些。


1
@Andrew:你做过基准测试吗?也许情况已经改变了,但上次我做基准测试时发现虚拟方法实际上更快。我没想到会这样,但事实就是这样。 - Jon Skeet
@Jon - 没有!我得检查一下以确保。 - Andrew Hare
1
@AndrewHare- Jon的链接导致了一个505错误。 - TheGeekZn

16

在您的情况下,最好保留类型转换,因为.ToString()可能会隐藏错误。例如,您的数据库架构已更改,名称不再是字符串类型,但使用.ToString(),代码仍然可以工作。所以在这种情况下,最好使用类型转换。

这是String.ToString()的实现 - 没有什么特别的 =)

public override string ToString()
{
    return this;
}

5

我想再做一个评论。

如果你要使用类型转换:string name = (string)DataRowObject["name"],那么在数据库表中的记录有空值的情况下,你会收到一个异常:无法将类型为“System.DBNull”的对象强制转换为类型“System.String”。

在这种情况下,你必须使用:string name = DataRowObject["name"].ToString() 或者

你必须检查空值。

if(!string.IsNullOrEmpty(DataRowObject["name"].ToString()))
{
string name = (string)DataRowObject["name"];
}
else
{
//i.e Write error to the log file
string error = "The database table has a null value";

}

5

向下转型是相对较慢的操作,因为CLR必须执行各种运行时类型检查。但在这种特定情况下,将其强制转换为 string 比调用 ToString()更为合适,以保持一致性(您无法在 object 上调用 ToInt32 ,但可以将其转换为 int ),并易于维护。


它可能没有你想象的那么慢 - 请看我的回答。 - Andrew Hare

3
对于数据对象,我建议您使用以下代码中的“as”关键字。
string name = DataRowObject["name"] as string;

在使用值之前,请先进行检查。

if(name != null)
{
    // statement for empty string or it has value
}
else
{
    // statement for no data in this object.    
}

这是否是同样含义的更简洁的版本:string name = (row["name"] as string) ?? "default"; - memnoch_proxy

2
在这种情况下:
string name = DataRowObject["name"].ToString();

由于它是一个字符串,我认为字符串对象的ToString()方法很简单:

return this;

我个人认为,这并不会对性能造成影响。
PS:我是一名Java程序员,所以这个回答只是猜测。

我认为 DataRowObject 没有类型知识,将所有内容作为对象存储,因此它绝对不像返回 this 那么简单。 - martijn_himself
3
@martjin_himself,欢迎来到面向对象编程世界,让我为您介绍一个新朋友:多态性。 - fortran
@fortran,您能详细解释一下吗?我知道所有东西都是对象,多态性允许您将字符串视为对象处理,但除非我漏掉了什么,否则这与此无关。谢谢。 - martijn_himself
@dfa 不好意思,我原本的意思是它并不以字符串形式存储,如果我的评论听起来有点刺耳,我希望能够编辑它们。 - martijn_himself

1

ToString()默认情况下不执行强制转换。它的目的是返回表示类型的字符串 (例如 "System.Object")。

如果你想避免强制转换,可以尝试考虑一种强类型实现方式(例如使用泛型)并完全避免DataRowObject。


1
我知道你提到过对象是一个字符串,但是如果你担心返回的对象为空,你也可以使用 "Convert.ToString(DataRowObject["name"]);" 进行强制转换。这样做的好处是,如果对象为空,它会返回一个空字符串(string.empty),以避免任何空引用异常(除非当然你希望在这种情况下抛出异常)。

使用“Convert.ToString”的另一个好处是,您可以传递空值而不会引发异常。[链接](http://msdn.microsoft.com/en-us/library/astxcyeh.aspx) - Remy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接