C# 基础学习4(is和as,执行就近原则,Equals,类型转换,string.Empty,const)

1,is和as
is是判断类型(返回bool值),as是转换类型(返回相应的类型或null)。
is操作符首先核实obj是否兼容于ClassA 类型。如果是,那么在if语句内部执行类型转换时,CLR再次核实obj是否引用一个ClassA。检查对象的类型,是个耗费资源的操作,首先要判断对象的实际类型,然后必须遍历继承树结构(层次结构),去与每个基类核对。
使用checked可以检测强制转换的不报错问题。

2,继承的执行就近原则
执行就近原则:对于同名字段或者方法,编译器是按照其顺序查找来引用的,也就是首先访问离它创建最近的字段或者方法,即从父类里开始找。
如下:Fruit是父类,Apple是子类
Fruit fruit(引用部分) = new Apple()对象部分;
当使用fruit调用同名的函数时,如果是override,那将调用对象部分的函数(即Apple),如果仅仅是同名字段或方法(即new),那将调用引用部分的函数(即Fruit),即执行就近原则。

3,Equals
Equals与==是一样的,对于
Equals:对于值类型,比较值类型的值是否相同。对于引用类型,比较变量的  ”内容” 是否一样(但前提是重写Equals方法,使得引用类型比较内容是否一致,如果没有重写Equals方法,那就是比较地址是否一样,即,是否是指向同一个对象)。
==:对于值类型,比较值类型的值是否相同。对于引用类型,比较其引用地址是否一样,即,是否是指向同一个对象。

测试如下:
public class FruitTest
{
    int apple;
    public FruitTest(int num)
    {
        apple = num;
    }
}
    void Fun1()
    {
        FruitTest i = new FruitTest(10);
        FruitTest j = new FruitTest(10);
        FruitTest k = j;
        print("i.Equals(j) :" + i.Equals(j));//false 调用的是父类Object的Equals方法,在Object默认的Equals实现中,比较的是两个对象是否指向了同一个引用。
        print("i==j " + (i == j));//false 引用类型比较地址是否相同,肯定为false
        print("k.Equals(j) :" + k.Equals(j));//true 比较引用类型指向的是否是同一个实例
        print("k==j " + (k == j));//true 引用类型比较地址是否相同,肯定为true
    }
    void Fun2()
    {
        string s1 = "abc";
        string s2 = "abc";
        string s3 = s2;
        print("s1==s2 " + (s1 == s2));//true (这种说法应该是对的:CLR 会维护一个字符串池,下面有详细说明)。(这种说法应该是错误的:因为重写了该操作符,所以是比较引用指向的值是否相同,这种说法的作者说反编译是这样的)
        print("s1.Equals(s2) " + s1.Equals(s2));//true 
        print("s3==s2 " + (s3 == s2));//true 
        print("s3.Equals(s2) " + s3.Equals(s2));//true
    }

值得一看的一篇文章 https://www.cnblogs.com/leipei2352/archive/2011/05/25/2056150.html 迷惑的C#中的Object.Equals静态方法
object.Equals方法,一篇文章这样写: 
    用反编译工具反编译System.dll得到方法的实现源码: 
    public static bool Equals(object objA, object objB) 
    { 
          if (objA == objB) 他首先使用了 == 符号进行对比  然后又 使用对象自己 的 Equals 进行对比
         { return true; } 
         if ((objA != null) && (objB != null)) 
         { return objA.Equals(objB); }  objA使用的Equals方法是 类型自己可能会重写 父类的 Equals 的这个方法.
        return false; 
     } 
可以看到,两个对象是否Equals,就要看其用等号判断的值是否相等.而等号判断两个对象是否相等是看他们两个对象是否有相同的引用(是否指向的是内存中的同一个对象的位置).虽然两个对象状态相同,但是,并没有指向内存中相同区域,不属于相同引用.因此返回值是False.

Object.Equals虚方法:
这里我们强调下,在Object默认的Equals(Object.Equals虚方法)实现中,比较的是两个对象是否指向了同一个引用。摘抄自该文:https://www.cnblogs.com/kym/archive/2010/01/21/1652869.html 重写Object的虚方法,重写Equals和运算符

4,类型转换
Parse(string s):内容必须为数字字符串,不能为null,"",否则报异常错误。如:int.Parse("123")。

TryParse(string s, out Int32 result):效果与Parse()一致,转换失败时不引发异常错误,最后一个参数result是输出值,如果转换成功则输出相应的值,转换失败则输出0。如:double.TryParse("123t", out result);此时result的值为0。

ToString():int i,i.ToString()转换为string类型。ToString(string format)按照格式转化成string类型。比如:result=123,result.ToString("C")打印为$123.00。

Convert:可用于多种类型之间相互转换,如果转换不符合条件,会异常报错(如:“123t”)。
变量为null的话,转换为0。只有引用型的变量可以为null,如:string s = null。
变量为string.Empty或""时转换为值类型,会异常报错。
对于float类型做四舍五入(一个现象123.5=124,123.45=123。所以应该是只看小数点后一位)。
用法:string s = "123";print(Convert.ToInt32(s));

():强制转换,将float转换int时,只截取整数部分。

思考:Convert.ToInt32(""或string.Empty)参数为字符串空时为什么会报错?
public static readonly String Tmp = "123";//正常
print(string.Empty);//正常
Convert.ToInt32(null);//正常
为什么public static readonly String Empty会报错呢?
不知道。

5,string.Empty和""和null
参考文章 https://www.cnblogs.com/instance/archive/2011/05/24/2056091.html C#中字符串的内存分配与驻留池
string.Empty 的内部实现是等于 ""。string.Empty 与 "" 在用法与性能上基本没区别。string.Empty 是在语法级别对 "" 的优化。CLR 会维护一个字符串池,以防在堆中创建重复的字符串,对string类的静态字段Empty的访问都会被指向同一引用,以节省内存空间。如果操作不会到驻留池中去检查,则会有多份string副本同时存在在内存中。比如:
string s1 = "123";//在堆中创建一个对象
string s2 = "123";//到堆里去找是否存在一个"123"相同内容的对象
print(((object)s1)==((object)s2)); //true s1和s2指向同一个对象
StringBuilder sb = new StringBuilder();
sb.Append("12").Append("3");
string s3 = sb.ToString();//重新开辟内存空间
print(((object)s3) == ((object)s2));//false ToString()方法不会到驻留池中去检查符串是否已经存在,所以不会让s3指向驻留池内的对象
 int i = 123;
string s4 = i.ToString();//重新开辟内存空间
print(((object)s4) == ((object)s2));//false ToString()方法不会到驻留池中去检查符串是否已经存在,所以不会让s4指向驻留池内的对象

string.Empty 和 "" 在栈和堆上都分配了空间,而 null 只在栈上分配了空间,在堆上没有分配,也即变量不引用内存中的任何对象。null 是引用类型变量的默认值。那么也只有引用型的变量可以为null。

 

6,const和readonly
摘抄自:https://www.cnblogs.com/liujie2272/p/5465255.html C#基础知识七之const和readonly关键字
静态常量:所谓静态常量就是在编译期间会对变量进行解析,再将常量的值替换成初始化的值。比如:const。
动态常量:所谓动态常量就是编译期间会将变量标记只读常量,而不用常量的值代替,这样在声明时可以不初始化,可以延迟到构造函数初始化。比如:readonly。

const修饰的常量在声明时必须初始化值;readonly修饰的常量可以不初始化值,且可以延迟到构造函数。
cons修饰的常量在编译期间会被解析,并将常量的值替换成初始化的值;而readonly延迟到运行的时候。
const修饰的常量注重的是效率;readonly修饰的常量注重灵活。
const修饰的常量没有内存消耗;readonly因为需要保存常量,所以有内存消耗。
const只能修饰基元类型(编译器直接支持的数据类型)、枚举类、或者字符串类型;readonly却没有这个限制。
const 对于引用类型的常量,可能的值只能是 string 和 null。
const编译后就是static常量了,不能使用static变量。readonly修饰的在构造函数中被赋值后就不可以改变。

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值