zoukankan      html  css  js  c++  java
  • C# 运算符和类型强制转换(6) 持续更新

    C#支持的运算符

    https://msdn.microsoft.com/zh-cn/library/6a71f45d(v=vs.140).aspx

    checked 和 unchecked

    byte b = 255;
    b++;
    Console.WriteLine(b);

    byte数据类型 范围 0~255。递增 b 的值会导致溢出。CLR如何处理这个溢出取决于很多因素,包括编译器选项。

    可以使用代码块标记 checked,发生溢出,抛出 OverflowException 异常。

    byte b = 255;
    checked
    {
        b++; 
    }
    Console.WriteLine(b);

    也可以用  /checked  编译器选项进行编译,就可以检查程序中所有未标记代码中的溢出。

    反之 unchecked 不检查溢出,注意 unchecked 是默认行为。

    byte b = 255;
    unchecked
    {
        b++; 
    }
    Console.WriteLine(b);

    is运算符

    检查对象是否是该该类型,或者派生自该类型。

     int value = 25;
     Console.WriteLine( (value is int) + "    " + (value is object));

    as 运算符

    执行引用类型的显示类型转换。如果类型不兼容,返回null。

    object str = "Hello";
    object value = 12;
    string str1 = str as string;
    string value2 = value as string;

    value2 等于 null

    sizeof运算符

    确定在栈中值类型需要的字节大小。

    Console.WriteLine( sizeof(int) );

    如果是复杂类型(和非基本类型)使用sizeof运算符,需要放在 unsafe 代码块中。

    unsafe
    {
        Console.WriteLine(sizeof(Customer));
    }

    typeof 运算符

    返回表示特定类型的 System.Type 对象。如 typeof(string) 返回表示 System.String 类型的Type对象。

    可空类型运算符

    int? v1 = null;
    int? a = v1 + 2; // a  = null

    空合并运算符

    int? v1 = null;
    v1 = v1 ?? 10;
    Console.WriteLine(v1);

    运算符优先级

    一般情况避免利用运算符优先级来生成正确结果,用圆括号指定运算符执行顺序。

    类型安全

    中间语言(IL)对代码实现强制实现强类型。

    强类型语言在没有强制类型转换前,不允许两种不同类型的变量相互操作。

    类型转换

    byte byte1 = 10;
    byte byte2 = 20;
    byte count = byte1 + byte2;
    Console.WriteLine(count);

    这里编译时,提示您 byte count 改成 int count。只是因为 两个 byte类型 相加 返回 int 类型,这时就需要类型转换了。

    1、隐式转换

    只要能保证值不会发生任何变化,类型转换就开自动(隐式)进行。

    long count = byte1 + byte2;

    2、显示转换类型

    byte count =(byte) (byte1 + byte2);

    要小心的时候显示转换类型,还要注意防止丢失数据。更不能转换 null 。

    如果要 字符串 转换 为 int 时

    string str = "100";
    int i = int.Parse(str);
    str = i.ToString();

    装箱和拆箱

    装箱用于描述把一个值类型转换为引用类型。

    拆箱把引用类型转换为值类型。

    比较引用类型的相等性

    ReferenceEquals

    两个版本 Equals 

    比较运算符(==)

    1、ReferenceEquals

    ReferenceEquals是一个静态方法,测试两个引用类的同一个实例,判断两个引用是否包含内存中的相同地址。

    2、虚函数 Equals

    因为是虚函数,所以需要在类中重写它,比较。比较方式可以通过值。如果需要用类的实例用作字典中的键,那么需要重写 Object.GetHashCode() 的方式,注意此方式效率非常低的。

    3、静态函数 Equals

    有两个参数,如果两个引用实际上引用了某个对象,它就调用虚函数 Equals 实例方法。这表示重写了 虚函数 Equals ,也重写了静态版本函数。

    4、比较运算符 ==

    比较值和比较引用。

    ReferenceEquals 用于比较引用,Equals 用于比较值,比较运算符看作一个中间项。ReferenceEquals应用值类型时,总是返回false。因为值类型需要装箱到对象中。

    System.ValueType 提供的 Equals 的默认重写版本肯定足以应付绝大多数自定义的结构,但仍可以针对自己的接口再次重写它,以提供性能。

    运算符重载

    重载不仅仅限于算术运算符。还可以 重载比较运算符 ==、< 。等 语句 if(a==b) 默认比较引用,对于 string,比较字符串是否相同。

    struct Vector
    {
        public double x, y, z;
    
        public Vector(double x, double y, double z)
        {
            this.x = x;
            this.y = y;
            this.z = z;
        }
    
        public Vector(Vector rhs)
        {
            x = rhs.x;
            y = rhs.y;
            z = rhs.z;
        }
    
        public override string ToString()
        {
            return x + " " + y + " " + z;
        }
    
        public static Vector operator +(Vector lhs, Vector rhs)
        {
            Vector result = new Vector(lhs);
            result.x += rhs.x;
            result.y += rhs.y;
            result.z += rhs.z;
            return result;
        }
    
        public static Vector operator *(Vector lhs, double rhs)
        {
            return new Vector(rhs * lhs.x, rhs * lhs.y, rhs * lhs.z);
        }
    }

    一般运算符左边参数命名 lhs,运算符右边命名 rhs。

    Vector vector1, vector2, vector3;
    vector1 = new Vector(4.0, 3.0, 1.0);
    vector2 = new Vector(4.0, -3.0, -1.0);
    vector3 = vector1 + vector2;
    Console.WriteLine(vector3);

    与C++语言不同,C#不允许重载 "=" 运算符,但如果重载 "+" 运算符,编译器自动使用 "+" 运算符的重载执行 += 匀速符操作。

    比较运算符重载

    • == 和 !=
    • > 和 <
    • >= 和 <=

    如果重载了 "==",就必须重载 "!=" 。另外,比较运算符必须返回布尔类型的值。

    重载 "==" 和 "!=" 时,必须重载 System.Object 中继承 Equals 和 GetHashCode 方法,否则会产生一个编译警告。原因是Equals方法实现与"=="运算符相同类型的相等逻辑。

    public static bool operator ==(Vector lhs, Vector rhs)
    {
        if (lhs.x == rhs.x && lhs.y == rhs.y && lhs.z == rhs.z)
        {
            return true;
        }
        else
        {
            return false;
        }
    }
    
    public static bool operator !=(Vector lhs, Vector rhs)
    {
        return !(lhs == rhs);
    }
    
    public override bool Equals(object obj)
    {
        return base.Equals(obj);
    }
    
    public override int GetHashCode()
    {
        return base.GetHashCode();
    }

    用户自定义的类型强制重载

    c#允许定义自己的数据类型(结构和类),并可以在自定义数据类型之间进行类型强制转换。

    public static implicit operator float(Currency value)
    {
        return (float) value;
    }

    这里定义的类型强制转换可以隐式地把Currency型的值转换为float型。

    implicit 声明 数据类型转换为隐式的,编译器就可以隐式或显式的使用这个转换。

    explicit 声明为显式的使用它。

    public static explicit operator Celsius(Fahrenheit fahr)
    {
        return new Celsius((5.0f / 9.0f) * (fahr.degrees - 32));
    }
    
    Fahrenheit fahr = new Fahrenheit(100.0f);
    Console.Write("{0} Fahrenheit", fahr.Degrees);
    Celsius c = (Celsius)fahr;

    类型强制转换必须同时声明为 public 和 static。

    https://msdn.microsoft.com/zh-cn/library/xhbhezf4.aspx

    C++中,类型强制转化针对于类的实例成员。

    示例

         struct Currency
         {
            public uint Dollars;
            public ushort Cents;
            
            public Currency(uint dollars, ushort cents)
            {
               this.Dollars = dollars;
               this.Cents = cents;
            }
            
            public override string ToString()
            {
               return string.Format("${0}.{1,-2:00}", Dollars,Cents);
            }
    
    
            // 隐式转换
            public static implicit operator float(Currency value)
            {
                return value.Dollars + (value.Cents / 100.0f);
            }
    
            // 显示转换
            public static explicit operator Currency(float value)
            {
                uint dollars = (uint)value;
                ushort cents = (ushort)((value - dollars) * 100);
                return new Currency(dollars, cents);
            }
    
         }
    
    
      static void Main(string[] args)
      {
         try
         {
            Currency balance = new Currency(50,35);
            
            Console.WriteLine(balance); // 转换为 float
            Console.WriteLine("balance is " + balance);  // 隐式调用 toString
            Console.WriteLine("balance is (using ToString()) " + balance.ToString());  // 显示调用 toString
            
            float balance2 = balance; // 隐式转为 float
            
            Console.WriteLine("After converting to float, = " + balance2);
            
            balance = (Currency) balance2; // 显示转为 Currency
            
            Console.WriteLine("After converting back to Currency, = " + balance);
            Console.WriteLine("Now attempt to convert out of range value of " +
                              "-$50.50 to a Currency:");
            
            checked
            {
               balance = (Currency)(-50.50);  // 显示转为 Currency
               Console.WriteLine("Result is " + balance.ToString());
            }
         }
         catch(Exception e)
         {
            Console.WriteLine("Exception occurred: " + e.Message);
         }
    
         Console.ReadLine();
      }

    类型转换的语法对于结构和类一样的。

    类之间的类型强制转换

    定义不同结构或类的实例之间的类型强制是完全合法,也有限制:

    • 如果某个类派生自另一个类,就不能定义这两个类之间的类型强制转换(因为这些类型转换已存在)。
    • 类型强制必须在源数据类型或目标数据类型的内部定义。

    C#要求把类型强制转换的定义放在源类或目标类的内部。因为这样可以防止第三方类型强制转换引入类中。

    基类和派生类之间的类型强制转换

    MyBase 和 MyDerived。其中 Myderived 直接或间接派生自 MyBase 类。

    MyDerived derivedObject = new MyDerived();
    MyBase baseCopy = derivedObject;

    MyDerived 隐式地强制转换为 MyBase

    MyBase derivedObject = new MyDerived();
    MyBase baseObject = new MyBase();
    MyDerived derivedCopy1 = (MyDerived) derivedObject;  // OK
    MyDerived derivedCopy2 = (MyDerived) baseObject;     // Throws exception

    基类是不可以强制转为派生类。

    装箱和拆箱数据类型强制转换

    object derivedObject = new Currency(40);
    object baseObject = new object();
    Currency derivedCopy1 = (Currency) derivedObject; // OK
    Currency derivedCopy2 = (Currency) baseObject;     // Throws exception

    多重类型转换

     Currency balance = new Currency(10);
     long amount = (long) balance;
     double amountD = balance;

    Currency 定义了一个 float 的隐式转换,编译器又知道如何显式地从 float 强制转换为 long。所以 IL代码 首先把 balance 转换为 float,在把结果转换 long。类似这样。

    long amount = (long) (double)balance;
  • 相关阅读:
    扩展中国剩余定理学习笔记
    寻找宝藏
    卢卡斯定理学习笔记
    [国家集训]矩阵乘法
    中国剩余定理学习笔记
    [CTSC2018]混合果汁
    数据结构(C语言版)第二章2.82.11 动态链表
    数据结构(C语言版)第二章2.12.7
    C语言中换行符和回车符的区别(转)
    C的xml编程libxml2(转摘)
  • 原文地址:https://www.cnblogs.com/z888/p/5787305.html
Copyright © 2011-2022 走看看