日期:<?xml:namespace prefix = st1 ns = "urn:schemas-microsoft-com:office:smarttags" />2008-6-8
学习内容:泛型,装箱和拆箱,C#中的数据类型,C#中的字符
遗留问题:
学习总结:
1.       泛型的引入
using System;<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />

namespace ConsoleApplication3

{

    class Stack

    {

        private int[] items;//定义一个数组用于存储在栈中的值

        private int count;//定义一个变量存储栈中元素的个数

        public Stack(int size)//带参数的构造函数,初始化栈

        {

            items = new int[size];//给数组元素指定大小

            count = 0;

        }

        public void Push(int x)//成员方法,入栈

        {

            items[count++] = x;

        }

        public int Pop()//成员方法,出栈

        {

            return items[--count];

        }

    }

    class Test

    {

        static void Main(string[] args)

        {

            Stack s = new Stack(10);//声明一个Stack类的实例,栈的大小为10个元素

            s.Push(111);//调用Push方法将数据压入栈中

            s.Push(222);

            Console.WriteLine(s.Pop()+s.Pop());//调用Pop方法,是栈中的元素出栈,并使出栈的元素相加

        }

    }

}

如果用户的需求发生改变了,既想输入整数的值又想输入其他类型的数值该怎么办呢?第一种方法:继续重载第二种方法:引用object类 第三种方法:泛型

第二中方法的例子:

using System;

namespace ConsoleApplication3

{

    class Stack

    {

        private object[] items;//定义一个数组用于存储在栈中的值

        private int count;//定义一个变量存储栈中元素的个数

        public Stack(int size)//带参数的构造函数,初始化栈

        {

            items = new object[size];//给数组元素指定大小

            count = 0;

        }

        public void Push(object x)//成员方法,入栈

        {

            items[count++] = x;

        }

        public object Pop()//成员方法,出栈

        {

            return items[--count];

        }

    }

    class Test

    {

        static void Main(string[] args)

        {

            Stack s = new Stack(10);//声明一个Stack类的实例,栈的大小为10个元素

            s.Push(123);//调用Push方法将数据压入栈中

            s.Push(456);

            Console.WriteLine((int)s.Pop() +(int)s.Pop());//调用Pop方法,是栈中的元素出栈,并使出栈的元素相加

        }

    }

}

问题:如果用户先输入一个整型数,再输入一个浮点型的数,编译能通过,但运行时出现system.invalicastexcption异常,隐藏的缺陷,不容易发现错误。且在程序中出现了大量的装箱和拆箱操作,程序的性能下降

第三种方法的例子:

using System;

namespace ConsoleApplication3

{

    class Stack<T>

    {

        private T[] items;//定义一个数组用于存储在栈中的值

        private int count;//定义一个变量存储栈中元素的个数

        public Stack(int size)//带参数的构造函数,初始化栈

        {

            items = new T[size];//给数组元素指定大小

            count = 0;

        }

        public void Push(T x)//成员方法,入栈

        {

            items[count++] = x;

        }

        public T Pop()//成员方法,出栈

        {

            return items[--count];

        }

    }

    class Test

    {

        static void Main(string[] args)

        {

            Stack<string> s = new Stack<string>(10);//声明一个Stack类的实例,栈的大小为10个元素

            s.Push("123");//调用Push方法将数据压入栈中

            s.Push("445");

            Console.WriteLine(s.Pop() +s.Pop());//调用Pop方法,是栈中的元素出栈,并使出栈的元素相加

        }

    }

}

泛型的引用:大大减少了装箱和拆箱的操作,提高了程序的性能

查看是否进行了装箱和拆箱操作的方法:打开MIL 反汇编程序,打开编译后生成的.exe文件,即可查看

2.       装箱和拆箱
只有被装了箱的值类型,才能进行拆箱操作

3.       C#中的数据类型
C#中有两种类型:值类型和引用类型。值类型的变量直接包含它们中的数据,而引用类型的变量存储的是对它们数据的引用(即指向对象的指针),后者称为对象。
<?xml:namespace prefix = v ns = "urn:schemas-microsoft-com:vml" />
上图展示了C#中类型的组织结构,object类是各种类型的基类
引用类型在内存的托管堆中(包括同步块和方法表),值类型的对象分配在内存的堆栈中
using System;

namespace ConsoleApplication4

{

    class Myclass

    {

        public int i;

    }

    class Test

    {

        static void Main(string[] args)

        {

            Myclass mc = new Myclass();

            mc.i = 100;

            Myclass mc1 = mc;

            mc1.i = 200;

            Console.WriteLine("mc.i="+mc.i);

            Console.WriteLine("mc1.i="+mc1.i);

 

        }

    }

}

//输出结果mc.i=200,mc1.i=200

注意:mcmc1指向的是同一块托管堆

using System;

namespace ConsoleApplication4

{

    struct Myclass

    {

        public int i;

    }

    class Test

    {

        static void Main(string[] args)

        {

            Myclass mc = new Myclass();

            mc.i = 100;

            Myclass mc1 = mc;//拷贝的是mc的副本

            mc1.i = 200;

            Console.WriteLine("mc.i="+mc.i);

            Console.WriteLine("mc1.i="+mc1.i);

 

        }

    }

}

//输出结果mc.i=100,mc1.i=200

注意:值类型各有个的块

using System;

namespace ConsoleApplication4

{

    class Myclass

    {

        public int i;

    }

    class Test

    {

        static void Seti(Myclass m)

        {

            m.i = 300;

        }

        static void Main(string[] args)

        {

            Myclass mc = new Myclass();

            mc.i = 100;//在托管堆中分配存储空间存储100的值,在堆栈中存储的是指向100的地址

            Myclass mc1 = mc;//mc中的地址赋给mc1,让他也指向100

            Seti(mc1);//调用构造方法,让对象m也指向100,并修改他的值为300

            Console.WriteLine("mc.i="+mc.i);

            Console.WriteLine("mc1.i="+mc1.i);

 

        }

    }

}

//输出的结果为:mc.i=300,mc1.i=300

using System;

namespace ConsoleApplication4

{

    struct Myclass

    {

        public int i;

    }

    class Test

    {

        static void Seti(Myclass m)

        {

            m.i = 300;

        }

        static void Main(string[] args)

        {

            Myclass mc = new Myclass();

            mc.i = 100;//在堆栈中存储100的值

            Myclass mc1 = mc;//创建100的副本给mc1

            Seti(mc1);//创建100的副本给m,修改的是m中的i

            Console.WriteLine("mc.i="+mc.i);

            Console.WriteLine("mc1.i="+mc1.i);

 

        }

    }

}

//输出的结果为:mc.i=100,mc1.i=100

值类型的使用场合:

当类型是一个十分简单的类型,其中没有成员会修改类型的任何实例字段

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

类型不会派生出任何其他类型

类型的实例较小

类型不作为方法参数传递,也不作为方法的返回类型使用

4.      C#中的字符

.net framework中,字符总表示成16位的Unicode代码值,这简化了全球引用程序的开发。一个字符表示成System.char结构(一个值类型)的一个实例

using System;

using System.Collections.Generic;

using System.ComponentModel;

using System.Data;

using System.Drawing;

using System.Text;

using System.Windows.Forms;

 

namespace WindowsApplication2

{

    public partial class Form1 : Form

    {

        public Form1()

        {

            InitializeComponent();

        }

 

        private void button1_Click(object sender, EventArgs e)

        {

            string s;

            s = textBox1.Text;

            foreach (char c in s)

            {

                int i = (int)c;//将汉字强制转换为整型

                if (i < 0x4e00 || i > 0x9fa5)//汉字的十六进制的取值范围为0x9fa5-0x4e00

                    MessageBox.Show("用户名输入有误!");

            }

        }

    }

}