C#基础-第5章:基元类型、引用类型和值类型

 5 本章内容:

  1.  编程语言的基元类型
  2. 引用类型和值类型
  3. 值类型的装箱和拆箱
  4. ·对象哈希码 (暂无代码演示)
  5. dynamic基元类型

PS:以下代码以装箱和拆箱的说明居多

using System;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using System.Dynamic;
using System.Linq;
using Microsoft.CSharp.RuntimeBinder;

///////////////////////////////////////////////////////////////////////////////

public static class Program
{
    public static void Main()
    {
        PrimitiveDemo();
        BoxingDemo();
        ReferenceVsValue.Go();
        Boxing.Go();
        BoxingForInterfaceMethod.Go();
        MutateViaInterface.Go();
        DynamicDemo.Go();
    }

    private static void PrimitiveDemo()//P99-100
    {
        //以下4行都能正确的编译,并生成相同的IL代码
        int a = new int();                   //不方便的语法
        int b = 0;                           //最方便的语法
        System.Int32 c = new System.Int32(); //最不方便的语法
        Int32 d = 0;                         //方便的语法 Int32 int 是等价的

        // 显示全部变量为0
        Console.WriteLine("a = {0}, b = {1}, c = {2}, d = {3}",
           new Object[] { a, b, c, d });

        // 设置全部的值为5
        a = b = c = d = 5;
        Console.WriteLine("a = {0}, b = {1}, c = {2}, d = {3}",
           new Object[] { a, b, c, d });
    }

    private static void BoxingDemo()
    {
        Int32 a = 5;    // 创建未装箱的值类型变量
        Object o = a;   // o引用已装箱的a的版本
        a = 123;        // 修改未装箱的值 123
        Console.WriteLine(a + ", " + (Int32)o);  // 显示 "123, 5"
        Console.WriteLine(a + ", " + o);         // 优化

        Console.WriteLine(a);   // 没有装箱
    }

    //引用类型vs值类型
    private static class ReferenceVsValue
    {
        //引用类型 (因为 'class')
        private class SomeRef { public Int32 x; }

        // 值类型 (因为 'struct')
        private struct SomeVal { public Int32 x; }

        public static void Go()//P(107)
        {
            SomeRef r1 = new SomeRef();   // 在堆上分配
            SomeVal v1 = new SomeVal();   // 在栈是分类
            r1.x = 5;                     // 提领指针
            v1.x = 5;                     // 在栈上修改
            Console.WriteLine(r1.x);      // 显示 "5"
            Console.WriteLine(v1.x);      // 同样显示  "5"
            //图5-2的左半部分反映了执行以上代码之后的情况

            SomeRef r2 = r1;              // 只复制应用(指针)
            SomeVal v2 = v1;              // 在栈上分配并复制成员
            r1.x = 8;                     // r1.x 和 r2.x 都会改变
            v1.x = 9;                     // v1.x 会变,  v2.x 不变
            Console.WriteLine(r1.x);      // 显示 "8"
            Console.WriteLine(r2.x);      // 显示 "8"
            Console.WriteLine(v1.x);      // 显示 "9"
            Console.WriteLine(v2.x);      // 显示 "5"
            //图5-2的右半部分反映了执行以上所有代码之后的情况
                                          
        
        }
    }

    private static class Boxing
    {
        public static void Go()//P(111)
        {
            ArrayList a = new ArrayList();
            Point p;            //分配一个Point(不在堆中分配).
            for (Int32 i = 0; i < 10; i++)
            {
                p.x = p.y = i;   // 初始化值类型中的成员
                a.Add(p);        // 对值的类型装箱,将引用添加到ArrayLis中
            }
        }

        // 声明一个值类型
        private struct Point { public Int32 x, y; }

        public static void Main2()//P(113)
        {
            Int32 x = 5;
            Object o = x;         // 对x装箱,o引用已装箱对象
            Int16 y = (Int16)o;   // 抛出 InvalidCastException 异常
        }

        public static void Main3()//P(113)
        {
            /* Main2 方法正确的转化方式 */
            Int32 x = 5;
            Object o = x;                 // 对x进行装箱,o引用已装箱对象
            Int16 y = (Int16)(Int32)o;    // 先拆箱为正确类型,再转型
        }

        public static void Main4()
        {
            Point p;
            p.x = p.y = 1;
            Object o = p;   //对P进行装箱

            p = (Point)o;  //对o进行拆箱,将字段从已装箱实例复制到栈变量中
                          
        }

        public static void Main5()
        {
            Point p;
            p.x = p.y = 1;
            Object o = p;   // 对p进行装箱;o引用已装箱的实例

            // 将 Point的字段变成2
            p = (Point)o;   // 对o拆箱,将字段从已装箱的实例复制到栈变量中
            p.x = 2;        // 更改栈变量的状态
            o = p;          // 对p装箱;o引用新的已装箱实例
        }

        public static void Main6()//P(114)
        {
            Int32 v = 5;            // 创建未装箱值类型变量
            Object o = v;            // o引用已装箱的,包含值5的Int32
            v = 123;                 // 改变为装箱的的值改成123

            Console.WriteLine(v + ", " + (Int32)o); // 显示 "123, 5"
        }

        public static void Main7()//P(116)
        {
            Int32 v = 5;                // 创建未装箱值类型变量.
            Object o = v;               // o 引用v的已装箱版本

            v = 123;                    //将未装箱的值类型修改成123
            Console.WriteLine(v);       // 显示 "123"

            v = (Int32)o;               //拆箱并将o复制到v
            Console.WriteLine(v);       // 显示 "5"
        }

        public static void Main8()//P(117)
        {
            Int32 v = 5;   // 创建未装箱的值类型变量

#if INEFFICIENT
   // 编译下面这一行,v 被装箱3次,浪费时间和内存
   Console.WriteLine("{0}, {1}, {2}", v, v, v);
#else
            // 下面的代码结果一样,但无论执行速度,
            // 还是内存利用,都比前面的代码更胜一筹
            Object o = v;  // 对v手动装箱(仅一次)

            // 编译下面这一行不发生装箱
            Console.WriteLine("{0}, {1}, {2}", o, o, o);
#endif
        }
    }



    private static class BoxingForInterfaceMethod
    {
        private struct Point : IComparable //p(118)
        {
            private Int32 m_x, m_y;

            //构造器负责初始化字段
            public Point(Int32 x, Int32 y)
            {
                m_x = x;
                m_y = y;
            }

            //重写从System.ValueType 继承的ToString方法
            public override String ToString()
            {
                //如果调用了 base.ToString() 则会被装箱

                //将point做字符串返回。注意:调用ToString以避免装箱
                return String.Format("({0}, {1})", m_x, m_y);
            }


            // 实现类型安全的CompareTo方法
            public Int32 CompareTo(Point other)
            {
                // 利用勾股定理计算哪个point距离原点(0,0)更远
                return Math.Sign(Math.Sqrt(m_x * m_x + m_y * m_y)
                   - Math.Sqrt(other.m_x * other.m_x + other.m_y * other.m_y));
            }

            // 实现IComparable 的 CompareTo 方法
            public Int32 CompareTo(Object o)
            {
                if (GetType() != o.GetType())
                {
                    throw new ArgumentException("o is not a Point");
                }
                // 调用类型安全的ComareTo方法
                return CompareTo((Point)o);
            }
        }

        public static void Go() //P(119)
        {
            // 在栈上创建2个Point的实例
            Point p1 = new Point(10, 10);
            Point p2 = new Point(20, 20);
            
            // 调用ToString(虚方法)不装箱p1;
            Console.WriteLine(p1.ToString());   // 显示"(10, 10)"

            // 调用GetType(非虚方法)时,要对P1进行装箱
            Console.WriteLine(p1.GetType());    // 显示"Point"


            //调用CompareTo 不装箱p1
            //由于调用的是CompareTo(Point),所以p2不装箱 
            Console.WriteLine(p1.CompareTo(p2));    // "-1"

            // p1要装箱,引用放到c中
            IComparable c = p1;
            Console.WriteLine(c.GetType()); // 显示"Point"


            //调用CompareTo不装箱p1
            //由于CompareTo传递不是Point变量
            //所以调用的是CompareTo(Object),它要求获取对装箱Point的引用
            //c不装箱是因为本来就引用了已装箱Point
            Console.WriteLine(p1.CompareTo(c)); // 显示"0"

            // c不装箱,因为它本来就引用了已装箱Point
            // p2要装箱,因为调用的是CompareTo(Object)
            Console.WriteLine(c.CompareTo(p2)); // "-1"

            //对c拆箱,字段复杂到P2中
            p2 = (Point)c;
            // 证明字段已复制到P2中
            Console.WriteLine(p2.ToString());   // "(10, 10)"
        }
    }


    private static class MutateViaInterface
    {
        // 接口定义了Change方法
        private interface IChangeBoxedPoint
        {
            void Change(Int32 x, Int32 y);
        }

        // Point是值类型.
        private struct Point : IChangeBoxedPoint
        {
            private Int32 m_x, m_y;

            public Point(Int32 x, Int32 y)
            {
                m_x = x;
                m_y = y;
            }

            public void Change(Int32 x, Int32 y)
            {
                m_x = x; m_y = y;
            }

            public override String ToString()
            {
                return String.Format("({0}, {1})", m_x, m_y);
            }
        }

        public static void Go()
        {
            Point p = new Point(1, 1);

            Console.WriteLine(p);

            p.Change(2, 2);
            Console.WriteLine(p);

            Object o = p;
            Console.WriteLine(o);

            ((Point)o).Change(3, 3);
            Console.WriteLine(o);

            // 对p进行装箱,更改已装箱的对象,然后丢弃它
            ((IChangeBoxedPoint)p).Change(4, 4);
            Console.WriteLine(p);

            // 更改已装箱的的对戏,并显示它
            ((IChangeBoxedPoint)o).Change(5, 5);
            Console.WriteLine(o);

            /********************* 如果把Point 改成class 引用类型 就不存在装箱,拆箱的的转化,上面的结果就会发变化 ********************/
        }
    }

    private static class DynamicDemo
    {
        public static void Go()
        {
            ShowLoadedAssemblies("Assemblies loaded before use of dynamic");
            SimpleDynamic();
            ShowLoadedAssemblies("Assemblies loaded after simkple use of dynamic");

            Demo();
            ShowLoadedAssemblies("Assemblies loaded after all dynamic code runs");
            ExcelAutomation();
            DynamicStaticInvocations();
        }

        private static void ShowLoadedAssemblies(String caption)
        {
            Console.WriteLine(caption);
            foreach (Assembly a in AppDomain.CurrentDomain.GetAssemblies())
                Console.WriteLine("   " + a.GetName().Name);
            Console.WriteLine();
        }

        private static Int32 SimpleDynamic()
        {
            return ((dynamic)0) + 0;
        }

        private static void Demo() //P(129)
        {
            dynamic value;
            for (Int32 demo = 0; demo < 2; demo++)
            {
                value = (demo == 0) ? (dynamic)5 : (dynamic)"A";
                value = value + value;
                M(value);
            }

            Object o = 123;         // OK: 从Int32 隐形转型为Object(装箱)
            //Int32 n1 = o;        // Error: 不允许从Object到Int32的隐式转化
            Int32 n2 = (Int32)o;   // OK: 从Object显示转型为Int32(拆箱)

            dynamic d = 123;        // OK: 从 Int32 隐形转化为 dynamic(装箱)
            Int32 n3 = d;           // OK: 从 dynamic 隐式转为 Int32(拆箱) 

            try
            {
                var m = M(d);           // 注意: 'var m' 等同于 'dynamic m'
            }
            catch (RuntimeBinderException) { }
            var x = (Int32)d;       // 'var x' 等同于 'Int32 x'
            var dt = new DateTime(d);  // 'vat dt' 等同于 'DateTime dt'
        }

        private static void M(Int32 n) { Console.WriteLine("M(Int32): " + n); }
        private static void M(String s) { Console.WriteLine("M(String): " + s); }


        /// <summary>
        /// 构造一个 'dynamic' 的实例派生类,来动态调用类型的静态成员
        /// </summary>
        internal sealed class StaticMemberDynamicWrapper : DynamicObject //P(132)
        {
            private readonly TypeInfo m_type;
            public StaticMemberDynamicWrapper(Type type) { m_type = type.GetTypeInfo(); }

            public override IEnumerable<String> GetDynamicMemberNames()
            {
                return m_type.DeclaredMembers.Select(mi => mi.Name);
            }

            public override bool TryGetMember(GetMemberBinder binder, out object result)
            {
                result = null;
                var field = FindField(binder.Name);
                if (field != null) { result = field.GetValue(null); return true; }

                var prop = FindProperty(binder.Name, true);
                if (prop != null) { result = prop.GetValue(null, null); return true; }
                return false;
            }

            public override bool TrySetMember(SetMemberBinder binder, object value)
            {
                var field = FindField(binder.Name);
                if (field != null) { field.SetValue(null, value); return true; }

                var prop = FindProperty(binder.Name, false);
                if (prop != null) { prop.SetValue(null, value, null); return true; }
                return false;
            }

            public override Boolean TryInvokeMember(InvokeMemberBinder binder, Object[] args, out Object result)
            {
                MethodInfo method = FindMethod(binder.Name, args.Select(a => a.GetType()).ToArray());
                if (method == null) { result = null; return false; }
                result = method.Invoke(null, args);
                return true;
            }

            private MethodInfo FindMethod(String name, Type[] paramTypes)
            {
                return m_type.DeclaredMethods.FirstOrDefault(mi => mi.IsPublic && mi.IsStatic && mi.Name == name && ParametersMatch(mi.GetParameters(), paramTypes));
            }

            private Boolean ParametersMatch(ParameterInfo[] parameters, Type[] paramTypes)
            {
                if (parameters.Length != paramTypes.Length) return false;
                for (Int32 i = 0; i < parameters.Length; i++)
                    if (parameters[i].ParameterType != paramTypes[i]) return false;
                return true;
            }

            private FieldInfo FindField(String name)
            {
                return m_type.DeclaredFields.FirstOrDefault(fi => fi.IsPublic && fi.IsStatic && fi.Name == name);
            }

            private PropertyInfo FindProperty(String name, Boolean get)
            {
                if (get)
                    return m_type.DeclaredProperties.FirstOrDefault(
                       pi => pi.Name == name && pi.GetMethod != null &&
                       pi.GetMethod.IsPublic && pi.GetMethod.IsStatic);

                return m_type.DeclaredProperties.FirstOrDefault(
                   pi => pi.Name == name && pi.SetMethod != null &&
                      pi.SetMethod.IsPublic && pi.SetMethod.IsStatic);
            }
        }

        private static class StaticTestType
        {
            public static String Method(Int32 x) { return x.ToString(); }
#pragma warning disable 649 // 忽略警告 字段永远不会被赋值给,并且总是有它的默认值
            public static DateTime Field;
#pragma warning restore 649
            public static Guid Property { get; set; }
        }

        private static void DynamicStaticInvocations()
        {
            dynamic staticType = new StaticMemberDynamicWrapper(typeof(String));
            Console.WriteLine(staticType.Concat("A", "B"));  //动态调用String 的静态方法

            staticType = new StaticMemberDynamicWrapper(typeof(StaticTestType));
            Console.WriteLine(staticType.Method(5));
            staticType.Field = DateTime.Now;
            Console.WriteLine(staticType.Field);
            staticType.Property = Guid.NewGuid();
            Console.WriteLine(staticType.Property);
            
        }
    }

    private static void ExcelAutomation()
    {
#if ReferencingExcel // Microsoft.Office.Interop.Excel.dll
      var excel = new Microsoft.Office.Interop.Excel.Application();
      excel.Visible = true;
      excel.Workbooks.Add(Type.Missing);
      ((Range)excel.Cells[1, 1]).Value = "Text in cell A1";  // Put a string in cell A1
      excel.Cells[1, 1].Value = "Text in cell A1";  // Put a string in cell A1
#endif
    }
}


//////////////////////////////// End of File //////////////////////////////////

猜你喜欢

转载自www.cnblogs.com/eric-yuan/p/10218599.html