• 第1章 C#类型基础


    1.1值类型和引用类型

    1.1.1 值类型

    使用值类型之前需要对值类型的所有元素初始化(普通值类型和结构体)。

    结构还有一个特性:调用结构上的方法前,需要对其所有的字段进行赋值,为了避免对结构体中所有字段专门赋值,可以通过隐式声明的构造函数去创建一个结构类型变量(new)。(P5)

    1.1.2 引用类型

    而当使用new操作符时:rPoint1= new RefPoint(1);
    则会完成下面几件事:
    ❑在应用程序堆(Heap)上创建一个引用类型(ReferenceType)对象的实例,并为它分配内存地址。
    ❑自动传递该实例的引用给构造函数。(正因为如此,才可以在构造函数中使用this来访问这个实例。)
    ❑调用该类型的构造函数。
    ❑返回该实例的引用(内存地址),赋值给rPoint1变量。

    1.1.3 简单类型

    对于自定义的值类型,比如结构,就不能用“==”来判断它们是否相等,而需要在变量上调用Equals()方法来完成。

    1.1.4 装箱和拆箱

    简单来说,装箱就是将一个值类型转换成等价的引用类型。它的过程分为这样几步:

    1)在堆上为新生成的对象实例分配内存。该对象实例包含数据,但它没有名称。

    2)将栈上值类型变量的值复制到堆上的对象中。

    3)将堆上创建的对象的地址返回给引用类型变量。

    需要注意的是:拆箱操作需要显示声明拆箱后转换的类型。它分为两步来完成:

    1)获取已装箱的对象的地址。

    2)将值从堆上的对象中复制到堆栈上的值变量中。

    1.2 对象判等

    1.2.1引用类型判等

    实例方法Equals(Object obj),静态方法Equals(Object objA,Object objB),静态方法ReferenceEquals(Object objA,Object objB)

    ReferenceEquals()这个方法名就可以看出,它判断两个引用变量是不是指向了同一个变量,如果是,那么就返回true。这种相等叫做引用相等(rPoint1==rPoint2等效于ReferenceEquals)。因为它们指向的是同一个对象,所以对rPoint1的操作将会影响rPoint2。(P8)

    对于引用类型,即使类型的实例(对象)包含的值相等,如果变量指向的是不同的对象,那么也不相等。(P8)

    1.2.2简单值类型判等

    值类型都会隐式地继承自System.ValueType类型,而ValueType类型覆盖了基类System.Object类型的Equals()方法,在值类型上调用Equals()方法,会调用ValueType的Equals()。(P9)

    结构体变量不能直接用“==”去判断,编译会报错(P10)

    1.2.3 复杂值类型判断

    对堆上对象的成员(字段)进行一对一的比较,而成员又分为两种类型,一种是值类型,一种是引用类型。
    对于引用类型,去判断是否引用相等;对于值类型,如果是简单值类型,那么同前一节讲述的一样去判断;如果是复杂类型,那么当然是递归调用了;最终确定要么是引用类型要么是简单值类型。(P11)

    1.3 对象复制
    1.3.1 浅度复制
    当对对象进行一个浅度复制的时候,对于值类型成员,会复制其本身(值类型变量本身包含了所有数据,复制时进行按位复制);
    对于引用类型成员(注意它实际只是一个对象引用,指向了堆上的对象实例),仅仅复制引用,而不在堆上重新创建对象。因此,浅度复制结果就是:新对象的引用成员和复制对象的引用成员指向了同一个对象。(P12)

    当复制一个结构类型成员的时候,直接创建一个新的结构类型变量,然后对它赋值,就相当于进行了一个浅度复制,也可以认为结构类型隐式地实现了浅度复制。(P12)

    对于引用类型,采用Clone()实现浅度复制,复制后的对象和原先对象成了“连体婴”,它们的引用成员字段依然引用堆上的同一个对象。P(13)

    1.3.2 深度复制
    可以利用序列化/反序列化来对对象进行深度复制:先把对象序列化(Serialize)到内存中,然后再进行反序列化,通过这种方式来进行对象的深度复制。如果想将对象进行序列化,那么对象本身,及其所有的自定义成员(类、结构),都必须使用Serializable特性进行标记。P(13)

    1.4 不可变类型
    1.4.1 从类型设计谈起,Class还是Struct
    在数据较小的情况下,传值的效率更高一些;而在数据较大的时候,传引用占据更小的内存空间。(P15)
    1.4.2 数据不一致的问题
    1.4.3 常量性和原子性
    ❑对象的原子性:对象的状态是一个整体,如果一个字段改变,其他字段也要同时做出相应改变。
    ❑对象的常量性:对象的状态一旦确定,就不能再次更改了。如果想再次更改,需要重新构造一个对象。

    对于原子性,实施的办法是添加一个构造函数,在这个构造函数中为对象的所有字段赋值。而为了实施常量性,不允许在为对象赋值以后还能对对象状态进行修改,所以将属性中的set访问器删除,同时将字段声明为readonly。(P16)

    1.4.4 避免外部类型对类型内部的访问

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Runtime.Serialization.Formatters.Binary;
    using System.IO;
    using System.Text.RegularExpressions;
    
    namespace _.net之美
    {
        class Program
        {
            static void Main(string[] args)
            {
                string[] phones = { "110", "111" };
                Address a = new Address("四川", "成都", "610000", phones);
                try
                {
                    string[] b = a.Phones;
                    b[0] = "112";
                    //a = new Address("海南", "海口", "62055");
                }
                catch
                { 
                
                }
                phones[0] = "113";
                Console.WriteLine(a.ToString());
                Console.Read();
            }
            public struct Address
            {
                private readonly string province;
                private readonly string city;
                private readonly string zip;
                private readonly string[] phones;
                public Address(string province, string city, string zip,string[] phones)
                {
                    this.province = province;
                    this.city = city;
                    this.zip = zip;
                    this.phones = new string[phones.Length];
                    phones.CopyTo(this.phones, 0);
                    CheckZip(zip); // 验证格式
                }
    
                public string Province
                {
                    get { return province; }
                }
    
                public string City
                {
                    get { return city; }
                }
    
                public string Zip
                {
                    get { return zip; }
                }
    
                public string[] Phones
                {
                    get
                    {
                        string[] rtn = new string[phones.Length];
                        phones.CopyTo(rtn, 0);
                        return rtn; 
                    }
                }
    
                private void CheckZip(string value)
                {
                    string pattern = @"d{6}";
                    if (!Regex.IsMatch(value, pattern))
                        throw new Exception("inValid!");
                }
    
                public override string ToString()
                {
                    return string.Format("P:{0},C:{1},Z:{2},P:{3}", province, city, zip, phones[0]);
                }
            }
        }
    
    }
    View Code
  • 相关阅读:
    iOS开发时区缩写
    HTTPS工作原理-默写
    【Swift学习笔记-《PRODUCT》读书记录-CoreData数据存储】
    判断是否是满二叉树
    词向量
    百面机器学习|第一章 特征工程
    c++中创建二维数组的几种方法
    深度学习入门|第七章 卷积神经网络(三)
    深度学习入门|第六章与学习相关的技巧(二)
    深度学习入门|第七章卷积神经网络
  • 原文地址:https://www.cnblogs.com/liuslayer/p/5225815.html
Copyright © 2020-2023  润新知