标签:
1、
实际上,当我们使用字符串拼接时,是String调用了他的静态方法Concat,Concat接受object参数也就是说如果本来就是引用类型就可以直接传进去了,千万不要转为值类型。比如
Int a =0;
Object b =a;
Console.WriteLine(a+","+(int)b);
这样多进行了一次拆箱和装箱操作,会降低效率。
正确的代码应该是:
Console.WriteLine(a.ToString()+","+b);
这样不会引起任何装箱,拆箱操作。
2、
WriteLine提供了很多重载方法,也就是说,你传入任何单个方法都不会引起拆箱,装箱操作:
Int a =0;
Console.WriteLine(a);//不会引起拆箱,装箱操作,它调用了WriteLine(Int32)
而如果真要传入多个参数,可以使用WriteLine的匹配:
Int a=0,b=1,c=2;
Console.WriteLine("{0},{1},{2}",a,b,c);
这样同样不会引起拆箱,装箱操作。
3、
ToString方法返回的是引用类型,那么值类型调用会不会引起装箱呢?答案是不会。
只要我们重写了ToString方法,就不会引起装箱,通常,为了调用虚方法,CLR会通过调用"类型变量值指针"识别它的类型,然而值类型并没有这个东西,所以势必会造成一次装箱,但是如果用户重写了的话,那么CLR会用非虚的方法进行调用,所以并不会引起装箱操作。
而调用GetType方法则必须装箱,原因是这个是继承自Object类,虚方法必须调用"类型变量值指针"识别类型。
总而言之,确定方法传入参数是否会引起装箱操作的诀窍是看看方法接受什么类型的参数(废话)。
4、
来看下面这么一段代码,Point(有x,y两个字段)是用户自定义的Struct,他继承了IChangeBoxedPoint接口,接口有一个Change(修改x,y的值)方法:
Point p = new Point(1,1);
((IChangeBoxedPoint) p).Change(4,4);
那么p里面x,y的值是多少呢?答案是1,1。究其原因,CLR首先在栈上为p分配了空间,之后对p进行了装箱操作,也就是拷贝了一份p的实例到托管堆上,但是!change方法只修改了托管堆上的p实例之后就被垃圾回收机制回收了。
5、
对象的同一性和相等性,由于引用对象的比较有两种方式,一个是看看他们是否指向同一个对象,另一个是是否字段相等,对于第一种比较,应该使用Object的静态方法ReferenceEquals而不是==运算符或者Equals方法!
如果要获得安全的比较操作可以继承IEquatable接口以及重载==/!=运算符。
另外,如果实现了Equals方法,还请实现GetHashCode方法,并实现一个不错的哈希算法。
6、
协变和异变:
假设Child类派生自Parent类。
比如List<in T>我们可以这样写:
List<Child> l1 =new IList<Parent>();
如果是List<out T>可以这么写:
List<Parent> l2 =new IList<Child>();
但为了确保代码的可读性,请只在必要时使用协变和异变。
标签:
原文地址:http://www.cnblogs.com/blackerXHunter/p/4314140.html