请考虑以下代码:
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
}
Run Code Online (Sandbox Code Playgroud)
三种类型的铸造之间有什么区别(好吧,第三种不是铸造,但是你得到了意图).应该首选哪一个?
San*_*der 805
string s = (string)o; // 1
Run Code Online (Sandbox Code Playgroud)
如果不是,则抛出InvalidCastException.否则,分配给,即使是.o
string
o
s
o
null
string s = o as string; // 2
Run Code Online (Sandbox Code Playgroud)
分配null
给s
if o
是不是a string
或if o
is null
.因此,您不能将它与值类型一起使用(null
在这种情况下,操作员永远不会返回).否则,分配o
给s
.
string s = o.ToString(); // 3
Run Code Online (Sandbox Code Playgroud)
如果是,则导致NullReferenceException.无论什么类型,都会分配任何返回.o
null
o.ToString()
s
o
使用1进行大多数转换 - 它简单明了.我倾向于几乎从不使用2,因为如果某些东西不是正确的类型,我通常会发生异常.我只看到需要这种返回null类型的功能,其中设计糟糕的库使用错误代码(例如,返回null =错误,而不是使用异常).
3不是强制转换,只是一个方法调用.当您需要非字符串对象的字符串表示时使用它.
Qui*_*ome 340
Bla*_*rad 29
这真的取决于你是否知道是否o
是一个字符串以及你想用它做什么.如果你的评论意味着o
真的真的是一个字符串,我更喜欢直接(string)o
演员 - 它不太可能失败.
使用直接强制转换的最大优点是,当它失败时,你会得到一个InvalidCastException,它会告诉你几乎出了什么问题.
使用as
运算符,如果o
不是字符串,s
则设置为null
,如果您不确定并且想要测试,这很方便s
:
string s = o as string;
if ( s == null )
{
// well that's not good!
gotoPlanB();
}
Run Code Online (Sandbox Code Playgroud)
但是,如果您不执行该测试,则稍后将使用s
并抛出NullReferenceException.这些往往是比较常见和很多难以追查,一旦他们在野外发生了,因为几乎每行取消引用变量,可能会抛出一个.另一方面,如果你试图转换为值类型(任何基元或结构,如DateTime),你必须使用直接转换 - 这as
将无效.
在转换为字符串的特殊情况下,每个对象都有一个ToString
,所以如果o
不是null,你的第三个方法可能没问题,你认为该ToString
方法可能会做你想要的.
如果您已经知道它可以转换为什么类型,请使用C样式转换:
var o = (string) iKnowThisIsAString;
Run Code Online (Sandbox Code Playgroud)
请注意,只有使用C风格的强制转换才能执行显式类型强制.
如果你不知道它是否是所期望的类型,你要使用它,如果它是,使用的关键字:
var s = o as string;
if (s != null) return s.Replace("_","-");
//or for early return:
if (s==null) return;
Run Code Online (Sandbox Code Playgroud)
请注意,因为不会调用任何类型转换运算符.如果对象不为null且本机为指定类型,则它将仅为非null.
使用ToString()获取任何对象的人类可读字符串表示形式,即使它不能转换为字符串.
使用FindControl方法时,as.net中的as关键字很好用.
Hyperlink link = this.FindControl("linkid") as Hyperlink;
if (link != null)
{
...
}
Run Code Online (Sandbox Code Playgroud)
这意味着您可以对类型变量进行操作,而不必object
像使用直接强制转换那样对其进行转换:
object linkObj = this.FindControl("linkid");
if (link != null)
{
Hyperlink link = (Hyperlink)linkObj;
}
Run Code Online (Sandbox Code Playgroud)
这不是一件大事,但它节省了代码行和变量赋值,而且它更具可读性
'as'基于'is',这是一个在运行时检查对象是否是polimorphycally兼容的关键字(基本上如果可以进行转换),如果检查失败则返回null.
这两个是等价的:
使用'as':
string s = o as string;
Run Code Online (Sandbox Code Playgroud)
使用'是':
if(o is string)
s = o;
else
s = null;
Run Code Online (Sandbox Code Playgroud)
相反,c风格的强制转换也是在运行时进行的,但是如果无法进行强制转换则抛出异常.
只是添加一个重要的事实:
'as'关键字仅适用于引用类型.你做不到:
// I swear i is an int
int number = i as int;
Run Code Online (Sandbox Code Playgroud)
在这些情况下,你必须使用铸造.
看来两者的概念是不同的。
直接铸造
类型不必严格相关。它有各种口味。
感觉就像这个物体要变成别的东西了。
AS操作符
类型有直接关系。如:
感觉就像你将以不同的方式处理该对象。
样品和 IL
class TypeA
{
public int value;
}
class TypeB
{
public int number;
public static explicit operator TypeB(TypeA v)
{
return new TypeB() { number = v.value };
}
}
class TypeC : TypeB { }
interface IFoo { }
class TypeD : TypeA, IFoo { }
void Run()
{
TypeA customTypeA = new TypeD() { value = 10 };
long longValue = long.MaxValue;
int intValue = int.MaxValue;
// Casting
TypeB typeB = (TypeB)customTypeA; // custom explicit casting -- IL: call class ConsoleApp1.Program/TypeB ConsoleApp1.Program/TypeB::op_Explicit(class ConsoleApp1.Program/TypeA)
IFoo foo = (IFoo)customTypeA; // is-a reference -- IL: castclass ConsoleApp1.Program/IFoo
int loseValue = (int)longValue; // explicit -- IL: conv.i4
long dontLose = intValue; // implict -- IL: conv.i8
// AS
int? wraps = intValue as int?; // nullable wrapper -- IL: call instance void valuetype [System.Runtime]System.Nullable`1<int32>::.ctor(!0)
object o1 = intValue as object; // box -- IL: box [System.Runtime]System.Int32
TypeD d1 = customTypeA as TypeD; // reference conversion -- IL: isinst ConsoleApp1.Program/TypeD
IFoo f1 = customTypeA as IFoo; // reference conversion -- IL: isinst ConsoleApp1.Program/IFoo
//TypeC d = customTypeA as TypeC; // wouldn't compile
}
Run Code Online (Sandbox Code Playgroud)
“(string)o”将导致 InvalidCastException,因为没有直接转换。
“o as string”将导致 s 成为空引用,而不是抛出异常。
“o.ToString()”本身并不是任何类型的强制转换,它是一种由对象实现的方法,因此由 .net 中的每个类以这样或那样的方式对以下实例“执行某些操作”调用它的类并返回一个字符串。
不要忘记,为了转换为字符串,还有 Convert.ToString(someType instanceOfThatType) ,其中 someType 是一组类型之一,本质上是框架基本类型。
图2对于转换为派生类型是有用的.
假设a是动物:
b = a as Badger;
c = a as Cow;
if (b != null)
b.EatSnails();
else if (c != null)
c.EatGrass();
Run Code Online (Sandbox Code Playgroud)
会得到一个用最少的铸件美联储.
根据在此页面上运行的实验:http : //www.dotnetguru2.org/sebastienros/index.php/2006/02/24/cast_vs_as
(此页面有时会显示一些“非法引荐来源网址”错误,因此请刷新一下)
结论是,“ as”运算符通常比强制转换更快。有时快很多倍,有时快一点。
我个人认为“ as”也更易读。
因此,由于它既更快又更“安全”(不会抛出异常),并且可能更易于阅读,所以我建议始终使用“ as”。
归档时间: |
|
查看次数: |
144232 次 |
最近记录: |