<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />

 

一、       泛型

1.         使用泛型类型可以最大限度地重用代码、保护类型的安全以及提高性能。
2.         泛型最常见的用途是创建集合类。
3.         .NET Framework 类库在 System.Collections.Generic 命名空间中包含几个新的泛型集合类。应尽可能地使用这些类来代替普通的类,如 System.Collections 命名空间中的 ArrayList
4.         您可以创建自己的泛型接口、泛型类、泛型方法、泛型事件和泛型委托。
5.         可以对泛型类进行约束以访问特定数据类型的方法。
6.         关于泛型数据类型中使用的类型的信息可在运行时通过使用反射获取。

 

泛型简单理解就是把类型当做参数。
泛型参数命名准则:
1)        务必使用描述性名称命名泛型类型参数,除非单个字母名称完全可以让人理解它的含义。
2)        考虑使用T作为具有单个字母类型参数的类型的类型参数名。
3)        务必将T作为描述性类型参数名的前缀
4)        考虑在参数名中指示对此类型参数的约束。

 

泛型约束
    T:结构
    必须是值类型。
 static void Main(string[] args)

 {

     PrintType<int>(5);                          //正确的写法

     PrintType<string>(“泛型真伟大”);   //错误的写法

 }

static void PrintType<T>(T i) where T: struct

 {

    Console.WriteLine("类型:{0,-20}   值:{1}",i.GetType (),i);

}

T:类

类型参数必须是引用类型;这一点也适用于任何类、接口、委托或数组类型。 

 static void Main(string[] args)

 {

     PrintType<int>(5);                           //错误的写法

     PrintType<string>(“泛型真伟大”);   //正确的写法

 }

static void PrintType<T>(T i) where T: class

 {

    Console.WriteLine("类型:{0,-20}   值:{1}",i.GetType (),i);

}

Tnew()

类型参数必须具有无参数的公共构造函数。当与其他约束一起使用时,new() 约束必须最后指定。

class Program

    {

        static void Main(string[] args)

        {

             PrintType<Demo>(new Demo());

        }

        static void PrintType<T>(T i) where T: new()

        {

            Console.WriteLine("类型:{0,-20}   值:{1}",i.GetType (),i);

        }    

    }

    class Demo

    {       

    }

T<基类名>

类型参数必须是指定的基类或派生自指定的基类。 

class Program

    {

        static void Main(string[] args)

        {

            PrintType<Demo>(new Demo1());    //正确

            PrintType<Demo>(new Demo());     //正确

            PrintType<Demo1>(new Demo1());   //正确

            PrintType<Demo2>(new Demo2());   //错误

        }

        static void PrintType<T>(T i) where T:Demo

        {

            Console.WriteLine("类型:{0,-20}   值:{1}",i.GetType (),i);

        }    

    }

    class Demo

    {}

    class Demo1 : Demo

    {}

    class Demo2

    {}

T<接口名称>

类型参数必须是指定的接口或实现指定的接口。可以指定多个接口约束。约束接口也可以是泛型的。   

 class Program

    {

        static void Main(string[] args)

        {

            PrintType<IDemo>(new Demo());    //正确

            PrintType<Demo>(new Demo());     //正确     

        }

        static void PrintType<T>(T i) where T : IDemo

        {

            Console.WriteLine("类型:{0,-20}   值:{1}", i.GetType(), i);

        }

    }

    interface IDemo

    { }

    class Demo : IDemo

    { }

 

TU

T 提供的类型参数必须是为 U 提供的参数或派生自为 U 提供的参数。这称为裸类型约束。

 class Program

    {

        static void Main(string[] args)

        {

            PrintType<IDemo,Demo>(new Demo());     //错误

            PrintType<Demo,IDemo>(new Demo());     //正确

            PrintType<Demo, Demo>(new Demo());     //正确

        }

        static void PrintType<T,U>(T i) where T : U

        {

            Console.WriteLine("类型:{0,-20}   值:{1}", i.GetType(), i);

        }

    }

    interface IDemo

    { }

    class Demo : IDemo

    { }

可以对同一类型参数应用多个约束,并且约束自身可以是泛型类型

如下所示:

 

      static void PrintType<T>(T i) where T : class ,new ()

        {

            Console.WriteLine("类型:{0,-20}   值:{1}", i.GetType(), i);

        }

二、       反射

   一:对于程序集中的类,构造函数没有参数,方法也没有参数的反射

    

类库代码如下:

 namespace MyClassLibrary

{

    class MyClass

    {

  public void MyMethod()

      {

         Console.WriteLine("这是MyClass反射出来的!");

      }

    }

}

  用反射代码:

Assembly myass = Assembly.LoadFile(@"F:\MyClassLibrary.dll");//首先要把指定位置的程序集加载进来

object myobj = myass.CreateInstance("MyClassLibrary.MyClass");//从该程序集中创建指定类型的实例。这里是创建MyClass的一个实例相当于普通的new一个对象

MethodInfo mythod = myobj.GetType().GetMethod("MyMethod");//获取指定实例类型的方法并提供对方法元数据的访问

 mythod.Invoke(myobj, null);//根据指定的参数调用当前实例表示的方法,这里就是调用myobj实例的mythod中获取的方法。null表示没有参数。

结果是:这是MyClass反射出来的!

 

二:对于程序集中构造函数无参数而方法有参数的反射

QQ.txt文件内容

E:\MyClassLibrary.dll

MyClassLibrary.MyClass

MyClassLibrary.MyClass2

MyMethod

22

ss

 

类代码(命名空间为MyClassLibrary)

 class MyClass2

 {

    public void MyMethod(int a)

     {

        Console.WriteLine("这是MyClass2反射出来的!构造函数无参数,方法有参数,方法参数为:"+a);

     }

  }

 

代码:

 string[] DllArr = File.ReadAllLines(@"E:\QQ.txt", Encoding.Default);// 1读取配置文件信息

Assembly ass = Assembly.LoadFile(DllArr[0]);  // 2加载一个程序集即加载E:\MyClassLibrary.dll

object ob = ass.CreateInstance(DllArr[2]);      //3创建指定类型的实例即MyClassLibrary.Mylass2的实例

MethodInfo mti = ob.GetType().GetMethod(DllArr[3]);// 4获取指定类型对象中具有该名称的公共方法这里是指MyMethod方法

object[] dataInfo = new object[DllArr.Length - 5];  //5就是设置长度为1,因为参数只有一个所以保存一个值就可以了

dataInfo[0] = Convert.ToInt32(DllArr[ 4]);  //6直接将文档中的22赋值给它 也可以输入值

mti.Invoke(ob, dataInfo);       //7使用指定的参数调用当前实例的方法或构造函数 这里指调用ob实例的mti中指定的方法,第二个参数为方法或构造函数参数

 

结果为:这是MyClass2反射出来的!构造函数无参数,方法有参数,方法参数为:22

三:构造函数有参数,方法也有参数

文档就是上面的文档

类代码:(命名空间为MyClassLibrary)

    class MyClass

    {

        public MyClass(string a)

        {

            Console.WriteLine("这里是MyClass有参数的构造函数返回的值,值为:{0}",a);

        }

 

        public void MyMethod(int a,string s)

        {

            Console.WriteLine("这是MyClass反射出来的!第一个参数为:"+a+"第二个参数为:"+s);

        }

    }

 

代码:

      string[] DllArr = File.ReadAllLines(@"E:\QQ.txt", Encoding.Default);// 读取配置文件信息

     Assembly ass = Assembly.LoadFile(DllArr[0]);  // 加载一个程序集

     Type type = ass.GetType(DllArr[1]);                //获取程序集实例中指定名称的对象

     MethodInfo mti = type.GetMethod(DllArr[3]);//获取指定对象中具有该名称的公共方法

     ConstructorInfo cst = type.GetConstructor(new Type[] { typeof(string) });  //为构造函数添加值  ConstructorInfo 提供了对构造函数的访问权

     object ob = cst.Invoke(new Object[] { "Myclass" });//Myclass作为构造函数的参数

     object[] dataInfo = new object[DllArr.Length - 4];

     dataInfo[0] = Convert.ToInt32(DllArr[ 4]);  //直接赋值

     dataInfo[1] = (DllArr[5]).ToString();//直接赋值

     mti.Invoke(ob, dataInfo);       //使用指定的参数调用当前实例的方法或构造函数这里指调用ob实例的mti中指定的方法,第二个参数为方法或构造函数参数

结果:

这里是MyClass有参数的构造函数返回的值,值为:Myclass

这是MyClass反射出来的!第一个参数为:22第二个参数为:ss

 

三、       序列化

    .NET Framework 提供了两个序列化技术:

二进制序列化保持类型保真,这对于多次调用应用程序时保持对象状态非常有用。例如,通过将对象序列化到剪贴板,可在不同的应用程序之间共享对象。您可以将对象序列化到流、磁盘、内存和网络等。远程处理使用序列化,“按值”在计算机或应用程序域之间传递对象。

XML 序列化只序列化公共属性和字段,并且不保持类型保真。当您希望提供或使用数据而不限制使用该数据的应用程序时,这一点非常有用。由于 XML 是开放式的标准,因此它对于通过 Web 共享数据来说是一个理想选择。SOAP 同样是开放式的标准,这使它也成为一个理想选择。

序列化需要将要序列化的类等标记为可序列化的。

二进制序列化需要的命名空间

using System.Runtime.Serialization;

using System.Runtime.Serialization.Formatters.Binary;

    代码:

           序列化类
 [Serializable]
    public class Person
    {       
        public  int age;
        public bool Sex
        {  get;  set;  }
    }
序列化
 Person XiaoHong = new Person();
            XiaoHong.age = 18;
            XiaoHong.Sex = false;        
            IFormatter formatter = new BinaryFormatter();
Stream stream = new FileStream("F:/MyFile.bin", FileMode.Create, FileAccess.Write, FileShare.None);
            formatter.Serialize(stream, XiaoHong);
            stream.Close();
反序列化
 IFormatter formatter = new BinaryFormatter();
 Stream stream = new FileStream("F:/xh.bin", FileMode.Open, FileAccess.Read, FileShare.Read);
            Person XiaoHong = (Person)formatter.Deserialize(stream);
            stream.Close();
            MessageBox.Show(string .Format ("年龄:{0} 性别:{1}",XiaoHong .age ,XiaoHong .Sex ));