从文档中得知:
与强制类型转换类似,as 运算符可以将一个对象转换为指定类型。不同的是当转换失败时,它返回 null 而非抛出异常。更准确地说,以下表达式:
expression as type
等同于:
expression is type ? (type)expression : (type) null
那么为什么不选择一种方式呢?为什么要有两个转换系统?
除了表达式只被评估一次这一点略有不同。
我确信这个对象实际上属于另一种类型。将其转换为该类型,如果我错了,则崩溃程序。
我确信这个对象不属于另一种类型,但是有一种公认的方法可以将当前类型的值转换为所需类型。(例如,将int转换为short。)将其转换为该类型,如果转换实际上无法完成,则崩溃程序。
请参阅我的文章以获取更多详细信息。
https://ericlippert.com/2009/10/08/whats-the-difference-between-as-and-cast-operators/
as
与C++中的dynamic_cast
类似。 - kevinarpe效率和性能
执行类型转换的一部分是一些集成的类型检查; 因此,在实际强制类型转换之前加上显式类型检查是多余的(类型检查会发生两次)。使用as
关键字可以确保只执行一次类型检查。您可能会想“但它必须进行空值检查而不是第二个类型检查”,但与类型检查相比,空值检查非常高效且性能卓越。
if (x is SomeType )
{
SomeType y = (SomeType )x;
// Do something
}
相较而言,进行了两次检查
SomeType y = x as SomeType;
if (y != null)
{
// Do something
}
进行1x -- 空值检查与类型检查相比要更加廉价。
有时候您希望如果无法按预期进行转换,则使事情失败,而其他时候则不关心,并且只想丢弃给定对象(如果无法进行转换的话)。
这基本上是常规类型转换的更快版本,包裹在 try 块中;但 As
更易读,而且还能节省打字时间。
as
如何实现其 try/catch——您的回答和 TomTom 的回答在这个细节上有些冲突。 - STWAs<T>(object)
,对吗?) - Ken它允许快速检查,无需尝试/转换开销,这在某些情况下可能需要处理基于消息的继承树。
我经常使用它(获取消息,对特定子类型做出反应)。尝试/转换将显着变慢(每个通过的消息上有许多try/catch框架)- 我们谈论的是每秒处理200,000条消息。
as
确实会将操作包装在Try块中,但也许使用了更高效的转换机制? - STWas
有自己的try/catch,性能应该是可比的。 - Nelson Rothermel让我给你一些真实世界的场景,告诉你在哪些情况下会同时使用它们。
public class Foo
{
private int m_Member;
public override bool Equals(object obj)
{
// We use 'as' because we are not certain of the type.
var that = obj as Foo;
if (that != null)
{
return this.m_Member == that.m_Member;
}
return false;
}
}
而...
public class Program
{
public static void Main()
{
var form = new Form();
form.Load += Form_Load;
Application.Run(form);
}
private static void Form_Load(object sender, EventArgs args)
{
// We use an explicit cast here because we are certain of the type
// and we want an exception to be thrown if someone attempts to use
// this method in context where sender is not a Form.
var form = (Form)sender;
}
}
通常我根据代码的语义选择其中一种。
例如,如果您有一个对象,您知道它必须是字符串,则使用 (string)
,因为这表明编写代码的人确定该对象是一个字符串,如果不是,则我们已经有比运行时转换异常更大的问题。
如果您不确定对象是否属于特定类型但希望对其进行逻辑处理,则使用 as
。您可以使用 is
运算符后跟转换,但 as
运算符更有效率。
或许举例会更有帮助:
// Regular casting
Class1 x = new Class1();
Class2 y = (Class2)x; // Throws exception if x doesn't implement or derive from Class2
// Casting with as
Class2 y = x as Class2; // Sets y to null if it can't be casted. Does not work with int to short, for example.
if (y != null)
{
// We can use y
}
// Casting but checking before.
// Only works when boxing/unboxing or casting to base classes/interfaces
if (x is Class2)
{
y = (Class2)x; // Won't fail since we already checked it
// Use y
}
// Casting with try/catch
// Works with int to short, for example. Same as "as"
try
{
y = (Class2)x;
// Use y
}
catch (InvalidCastException ex)
{
// Failed cast
}
int x=SomeObject as int? ?? 0
。(翻译说明:原文已经非常简洁明了,为了保持其原意和准确性,我的翻译仅做必要的语法调整。) - Earlz