第五章基元数据,引用类型和值类型(CLR学习)

了解一下BinaryReader 和BinaryWirte基元类型:

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;

namespace ConsoleApp
{
    class Program
    {
        private const string FileName = "AppSetting.txt";
        static void Main(string[] args)
        {
            WriteDefaultValues();
            DisplyValues();
        }

        /// <summary>
        /// 按顺序写入
        /// </summary>
        public static void WriteDefaultValues()
        {
            
            using (BinaryWriter writer = new BinaryWriter(File.Open(FileName, FileMode.Create)))
            {
                writer.Write(1.250F);
                writer.Write(@"C:\Temp");
                writer.Write(10);
                writer.Write(true);
            }
        }
        /// <summary>
        /// 按顺序写入值进行读取
        /// </summary>
        public static void DisplyValues()
        {
            float aspectRatio;
            string tempDirectory;
            int autoSaveTime;
            bool showStatusBar;
            if (File.Exists(FileName))
            {
               
                using (BinaryReader reader = new BinaryReader(File.Open(FileName, FileMode.Open)))
                {
                    aspectRatio = reader.ReadSingle();
                    tempDirectory = reader.ReadString();
                    autoSaveTime = reader.ReadInt32();
                    showStatusBar = reader.ReadBoolean();
                }
                Console.WriteLine("float类型值: " + aspectRatio);
                Console.WriteLine("字符串类型值: " + tempDirectory);
                Console.WriteLine("int值: " + autoSaveTime);
                Console.WriteLine("布尔值: " + showStatusBar);
            }
        }
    }
}

  任何称为"类"的类型都是引用类型。所有值类型都称为结构或枚举

  结构都是抽象类型:System.ValueType的直接派生类;

  枚举都是System.Enum抽象对象派生的;后者又从System.ValueType.

 

  设计类型时,要仔细考虑类型是否应该定义值类型而不是引用类型。值类型有时能提供更好的性能。除非满足以下全部条件,否则不应将类型声明为值类型:

  1.类型具有基元类型的行为。也就是说,十分简单的类型,没有成员会修改类型的任何实例字段。也就是十分简单的类型,没有成员会修改类型的任何实例字段。如果类型没有过提供会更改其字段成,就说改类型是不可变(immutable)类型。

  事实上,许多值类型,建议将全部字段标记为readonly

  2.类型不需要从其他任何类型继承

  3.类型也不派生出其他任何类型

  4.类型的实例较小(16字节或更小)

  5.类型的实例较大(大于16字节),但不作为方法实参传递,也不从方法返回。

  6.由于不能将值类型作为基类型来定义新的值类型或者新类型的引用类型,所以不应该在值类型中引入任何新的虚方法。所有方法都不能抽象,所有方法都隐式密封的。

  

  CLR 如何控制类型中的字段

  为了告诉CLR应该怎样做,要为自己定义的类或结构应用System.Runtime.InteropService.StructLayoutAttribute特性。

  1.可向该特性的构造器传递LayoutKind.Auto,让CLR自动排序字段。

  2.也可传递LayoutKind.Sequential,让CLR保持你的字段布局。

  3.还可以传递LayoutKind.Explicit,利用偏移量在内存中显式排序字段。

  

  值类型的装箱和拆箱

    将值类型转换成引用类型要使用装箱机制。

    1.在托管堆中分配内存。分配的内存量是值类型各字段所需要的内存量,还要加上托管堆所有对象都有的两个额外成员(类型对象指针和同步块索引)所需的内存量。

    2.值类型的字段复制到新分配的堆内存。

    3.返回对象地址。现在该地址是对象引用,值类型成了引用类型。

    将引用类型转换成值类型要使用拆箱机制。

    1.获取已装箱的对象中各个字段的地址,这个过程称为拆箱(unboxing)

    2.将字段包含的值从堆复制到基于栈的值类型实例中。

  未装箱值类型比引用类型更"轻":

  1.不在托管堆上分配

  2.没有堆上的每个对象都有的额外成员:"类型对象指针"和"同步块索引"

  有于未装箱值类型没有同步块索引,所以不能使用System,Threading.Mointor类型的方法(或者C#lock语句)让多个线程同步对实例的访问。

 

  System.Object 类型中Equals的虚方法;如果要重写Equal,要考虑几个问题:

  1.如果Obj 实参为null,返回为false,因为调用非静态Equals方法时,this所标识的当前对象显然为null

  2.如果this 和obj实参引用同一个对象,就返回true.

  3.如果this和obj实参引用不同类型的对象,就返回false

  4.针对类型定义的美国实例字段,将this对象中的值与obj对象中的值进行比较。任何字段不相等,就返回false

  5.调用基类的Equal方法来比较它定义的任何字段。如果基类的Equals方法返回false,就返回false;否则返回ture

  重写的Equals要符合相等性的4个特征

  1.Equals 必须自反;X.Equals(x)肯定返回ture;

  2.Equals必须对称;x.Equals(y)和y.Equals(x)返回相同的值

  3.Equals必须可传递;x.Equals(y)返回true,y.Equals(z)返回true,则x.Equals(z)肯定返回true

  4.Equals必须一致。比较的两个值不变,Equals返回值(true或false)也不能变

  

  dynamic 基元类型(表示对象的操作将在运行时解析)

  1.字段,方法参数或方法返回值的类型是dynamic ,编译器会将该类型转换为System.Object,并在元数据中向字段,方法参数或返回类型应用System.Runtime.CompilerServices.DynamicAttribure的实例。

  2.局部变量被指定为dynamic,则变量类型也会成Object,但不会向局部变量应用DynamicAttribute,因为它限制在方法内部使用。

  3.泛型类(引用类),结构(值类型),接口,委托或方法的泛型类型实参也可以是dynamic类型。

  4.所有表达式都能隐式转型为dynamic,因为所有表达式最终都生成从Object派生的类型。

 注意点:

  1.对象类型要兼容要转换成的类型。

  2.dynamic和var区别:var 是声明局部变量只是一种简化语法,它要求编译器根据表达式推断具体数据类型。var关键字只能在方法内部声明局部变量

posted on 2015-10-14 11:52  紫色的冰  阅读(338)  评论(0编辑  收藏  举报