C#类型转化的五点心得

开发 后端
C#是一门强类型的语言。大家都写过很多以System.Object类型为参数的函数,在这些函数内部,我们经常要吧那些参数向下转型为其他类型。本文将介绍C#类型转化的五点心得。

对于这种C#类型转化我们通常用两种选择:使用as操作符,或者使用强制转型。当然还有一个做法是先用is测试转换是否可行,然后再用as或者强制转换。

本文主要给大家提醒一些使用C#类型转化时需要注意的地方,或许你更想弄清楚as和强制转换的区别和使用场景,不用着急,看完,本文你自己就知道答案了,那么上面提到的两种C#类型转化我们需要注意哪些呢?

1、as和is操作符都不执行任何用户自定义的转换。

2、对于强制转换,引用为空将会转换出错。

3、强制转换任意类型和自定义转换两种情况的IL代码展示有区别。

4、用户自定义转换只作用于对象的编译时类型。

5、as操作符不能应用于值类型。

6、foreach循环语句中使用强制类型转型。

下面我们逐一进行介绍说明:

1,我们先来看错误代码示例:

classA  
{  
 
}  
classC  
{  
publicstaticimplicitoperatorA(Ct)  
{  
returnnewA();  
}  
}  
classProgram  
{  
staticvoidMain(string[]args)  
{  
objecto=Factory.GetObject();  
//o为一个C类型:  
Aa=oasA;//转型失败,o的类型不是A  
}  

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.

代码已经很明显,我们不可以因为定义了C到A的强制转换,就使用as,对应用户自定义转换,我们只可以使用(A)o转换,其实自定义转换和自定义操作=、+、-、"、%等操作符是一样的机理,这样你就明白为什么用as不可以使用自定义转换了。


2,还是看一个错误示例:

classA  
{  
 
}  
classB:A  
{  
 
}  
classProgram  
{  
staticvoidMain(string[]args)  
{  
Bb;  
Aa=(A)b;  
}  
}  
问题不用多言,as可以解决这个问题。  
 
 
3,看一个示例:  
 
classA  
{  
 
}  
classC  
{  
publicstaticimplicitoperatorA(Ct)  
{  
returnnewA();  
}  
}  
classB:A  
{  
 
}  
classProgram  
{  
staticvoidMain(string[]args)  
{  
Aa=newB();  
Bb=(B)a;  
Cc=newC();  
a=(A)c;  
}  
}  
对于Bb=(B)a;的IL代码如下:  
 
IL_0008:castclassConsoleApplication1.B  
 
对于a=(A)c;的IL代码如下:  
 
IL_0015:callclassConsoleApplication1.AConsoleApplication1.C::op_Implicit(classConsoleApplication1.C)  
区别大家已经看到了,要说真正认识区别那么我们要继续谈“4、用户自定义转换只作用于对象的编译时类型。"  
 
4,看一个示例:  
 
classA  
{  
 
}  
classC  
{  
publicstaticimplicitoperatorA(Ct)  
{  
returnnewA();  
}  
}  
classB:A  
{  
 
}  
classProgram  
{  
staticvoidMain(string[]args)  
{  
Aa=newB();  
Bb=(B)a;  
objectc=newC();  
a=(A)c;//编译通过,运行失败!  
}  

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.
  • 63.
  • 64.
  • 65.
  • 66.
  • 67.
  • 68.
  • 69.
  • 70.
  • 71.
  • 72.
  • 73.
  • 74.
  • 75.
  • 76.
  • 77.
  • 78.
  • 79.
  • 80.
  • 81.
  • 82.

也许你从来没想过a=(A)c;编译会成功,运行会出错在这句,毕竟我们有一个显示类型C到类型A的转换操作,我们看看IL代码即可找到答案,

.methodprivatehidebysigstaticvoidMain(string[]args)cilmanaged  
{  
.entrypoint  
//Codesize28(0x1c)  
.maxstack1  
.localsinit([0]classConsoleApplication1.Aa,  
[1]classConsoleApplication1.Bb,  
[2]objectc)  
IL_0000:nop  
IL_0001:newobjinstancevoidConsoleApplication1.B::.ctor()  
IL_0006:stloc.0  
IL_0007:ldloc.0  
IL_0008:castclassConsoleApplication1.B  
IL_000d:stloc.1  
IL_000e:newobjinstancevoidConsoleApplication1.C::.ctor()  
IL_0013:stloc.2  
IL_0014:ldloc.2  
IL_0015:castclassConsoleApplication1.A  
IL_001a:stloc.0  
IL_001b:ret  
}//endofmethodProgram::Main 
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.

大家注意看IL_0015:castclassConsoleApplication1.A这句,这句说明自定义转换在编译时刻进行,也许你要问为什么不是第3条的:

IL_0015:callclassConsoleApplication1.AConsoleApplication1.C::op_Implicit(classConsoleApplication1.C)

因为objectc,c被定义为Object类型,那么强制转换在编译时刻去Object找是否存在自定义转换操作(注意,()转型时编译器优先考虑自定义转换,找不到才进行castclass),当然Object没有自定义转换为A的操作,那么就使用普通的强制转换castclass。好了现在我们知道了用户自定义转换只作用于对象的编译时类型,而普通的Bb=(B)a;强制转换可以作用到运行时刻。那么上面的错误如何去掉呢?对应代码修改为:

objectc=newC();  
Ccc=casC;  
a=(A)cc; 
  • 1.
  • 2.
  • 3.

现在运行正常通过,好了我们再次查看IL代码

IL_001c:callclassConsoleApplication1.AConsoleApplication1.C::op_Implicit(classConsoleApplication1.C)

到这大家对3和4点的认识应该很清楚了吧。

5、as操作符不能应用于值类型————省略!,鉴于这个点很简单,本人就不提供示例了,大家有兴趣可以自己试验下。

6、看代码示例:(以下代码摘自《EffectiveC#中文版改善C#程序的50中方法》——23页)

publicvoidUseCollection(IEnumerabletheCollection)  
{  
foreach(MyTypetintheCollection)  
t.DoStuff();  
}  
 
//上面代码等同于:  
 
publicvoidUseCollection(IEnumerabletheCollection)  
{  
IEnumeratorit=hteCollection.GetEnumerator();  
while(it.MoveNext())  
{  
MyTypet=(MyType)it.Current;  
t.DoStuff();  
}  

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.

通过查看IL代码我们可以确认foreach语句的转换是使用的强制转换操作,那么为什么呢?之所以使用强制转型,是因为foreach语句需要同时支持值类型和引用类型,这侧面说明我们的第5点as不支持值类型。

好了,5点C#类型转化说明已经解释完了,你现在还想问as和强制转换的区别和使用场景么?,欢迎提出批评、指正错误。

【编辑推荐】

  1. C#读取文件夹中的文件操作浅析
  2. C#读取文件夹下面的全部文件的实现
  3. C#读取文件内容另存的实现
  4. C#读取文件高效方法浅析
  5. C#读文本文件的冰山一角
责任编辑:彭凡 来源: xueit.com
相关推荐

2017-06-28 15:24:10

大数据数据分析心得

2017-07-05 18:10:23

大数据分析思路心得

2009-06-02 11:25:22

HibernateJPA映射

2009-08-12 18:28:49

C#强制类型转化

2009-08-18 10:59:46

C#枚举类型

2009-06-25 13:59:59

java认证FileFilter

2011-10-25 10:51:08

私有云虚拟化公有云

2013-09-11 16:29:02

产品经理产品运营

2009-08-25 13:57:09

C#泛型集合类型

2009-08-18 13:06:17

C#枚举类型

2009-08-25 16:32:24

C#语言

2013-08-13 14:11:23

2009-08-26 17:22:09

C#语言

2009-08-10 17:25:58

C#匿名类型

2009-09-04 13:37:44

C#货币格式

2009-08-13 13:03:52

C#结构体数组

2009-08-13 13:17:10

C#结构体数组

2011-01-04 09:34:23

LambdaC#

2009-08-03 13:34:06

自定义C#控件

2009-08-26 10:34:15

C#类型C#变量
点赞
收藏

51CTO技术栈公众号