C#高级编程    第四章:反射  /**/  ↑↓←→

//反射 : 反射描述了在运行过程中检查和处理程序元素的功能    /*程序元素:元数据*/

//Dll、exe 都是程序集(装配件)存放MSIL(微软中间语言/*反编译出来的东西*/)及元数据(包含类、属性以及类之间关系等数据的描述性信息)

//命名空间: System.Reflection /*Reflection : 反射*/

  类型为type类,获取类型的结构信息

      ConstructorInfo[] myConstructors = type.GetConstructors()     //类型为type类,获取类型的结构字段

      fieldInfo[] myfields = type.GetFiedles()              //类型为type类,获取类型的结构方法
  属性事件请参照MSDN

 

 

   type inType = typeof(int)  

Consle.WriteLine(intType.IsAbstract);    //获取一个值,通过该值指示Type是否为抽象类并且必须被重写

Console.WriteLine(intType.IsClass);      //获取一个值,通过该值指示Type是否是一个类,即不是值类型或接口

Console.WriteLine(intType.IsEnum);       //获取一个值,通过该值指示当前的Type是否表示枚举

Console.WriteLine(intType.Isprimitive);  //获取一个值,通过该值指示Type是否为基元类型之一

Console.WriteLine(intType.IsValueType);  //获取一个值,通过该值指示Type是否为值类型

 

//获取Type对象
{
 1、Myclass m = new Myclass();  Type type = m.GetType();
 2、Type type = typeof(Myclass);
}

 类型名:type.Name
 类型全名: type.FullName
 名称空间: type.NameSpace
 程序集全名: type.Assembly
 模块名:   type.Module
 基类名:   type.BaseType

   MemberInfo[] memberinfos = type.GetMembers();  //获得指定类型的所有公共成员


   foreach(MemberInfo item in memberinfos)
{
 Console.WriteLine("{0}:{1}",item.MemeberType,item);
                                           ↑           ↑
                                        成员类型       描述信息
}

   MethodInfo  info = type.GetMethod("MyFunction");
                                           ↑
                                         Myclass 中的一个方法

 


Assembly theSnapInAsm = Assembly.LoadFrom(path);//加载程序集;path:具体的路径

 Assembly theSnapInAsm=Assembly.Load(path);//通过给定程序集的长格式名称加载程序集。


     例子 {
   Assembly SampleAssembly = Assembly.Load
          ("SampleAssembly, Version=1.0.2004.0, Culture=neutral, PublicKeyToken=8744b20f8da049e3");

  }

 

反射的功能:
{
 1:!在运行时!判断任意一个对象所属的类      //!....!需要注意的地方

 2:!在运行时!构造任意一个类的对象

 3:!在运行时!判断任意一个类所具有的成员变量和方法

 4:!在运行时!调用任意一个对象的方法
}

 

 

 

 

 

 

 

    C#高级编程    第五章:委托和事件
///////////////////////////////委托 
//委托是一种特殊的!类(class)型!,用途是实现对一批签名相同返回值类型相同的方法的封装
//使用委托可以再运行时动态设定要调用的方法,不知道方法名称,也可以调用方法,执行(或调用)一个委托将执行该委托引用的方法
//单播委托:封装一个方法
//多播委托:封装多个方法

//定义委托语法:[访问修饰符]delegate 返回类型 委托名();
    例子:       public   delegate   int      Call (int num1,int num2);delegate:委派...为代表、代理


//实例化委托、调用委托
  实例化委托意味着使其指向(或引用)某个方法。
  例子:
   namespace Delegates
{
 //委托定义
 public delegate int Call(int num1,int num2);
 class Math
 {
  public int Multiply(int num1,int num2)
  {
   return num1*num2;
  }
  public int Divide(int num1,int num2)
  {
   return num1/num2;
  }
 }  
}
  class TestDelegates
{
 [STAThread]          //[STAThread]代表此程序是单线程的一般出现在2003中,在2005中被取消
 static void Main(string[] args)
 {
  int result;
  Call objCall;
  Math objMath= new Math();
  objCall=new Call(objMath.Multiply);//委托的实例化:(要联系的对象)//单播委托   !在实例化第一个委托时用"="!
  //objCall+=new Call(objMath.Divide);//多播委托                                  !在实例化后面的委托时才用"+="!
  result=objCall(5,3);     //传参时用委托的()传参                     !单独调用委托时和调用事件一样  委托名()//具体例子第五章练习1!
  Console.WriteLint("结果为{0},"result);                                          
 }
}

 

//加深理解
 自定义的委托名字               自定义的ArrayList数组 里面放的全是startPumpCallback委托
foreach(StartPumpCallback callback in callbacks)
{
 callback();
}
///////程序不能停、不定时需要加方法并且方法的传入参数相同、返回值相同时考虑用委托

 


//////////////////////////////////////事件
//事件:事件允许一个对象在某一改变发生时通知另一个对象,其他对象可以注册一个事件,当事件发生时,他们被通知该事件已发生

 

//定义事件:
 [访问修饰符] event 委托名  事件名;
        //定义一个委托
 public delegate boid delegateMe();
 //定义一个事件
 private event delegateMe eventMe;//定义事件时!不加!()
 //事件只能在类中定义!

//订阅事件
 订阅事件只是添加了一个委托,事件引发时该委托调用一个方法
 objA方法订阅了事件 eventMe
 eventMe+=new delegateMe(objA.Method);
 objB 方法订阅了事件 eventMe
 eventMe+=new delegateMe(objB.Method);

//引发事件
 if(事件名(事件注册)!=null)
 {
  //引发eventMe事件
  eventMe(); 
 }

 

 

//事件参数:private void button1_Click(object sender, EventArgs e)
         (谁触发的,事件参数所包含的数据)//这是调用事件时
        {

        }
 
 public class CoreOverHeatingEventArgs:EventArgs//自定义的事件参数类必须继承EventArgs
 {
  private readonly int temperature;  //readonly 表示该字段在声明时赋值或在构造函数中赋值   在做它的属性时不用加readonly
  public CoreOverHeatingEventArgs(int temperature)
  {
   this.temperature=temperature;
  }
  public int GetTemperature()
  {
   return temperature;
  }
 }

 


//////////////////////////////////////总结(注意!)
!事件只可以封装一个委托! 因为在定义的时候就定死了 public event Restaurant.Call event1; //Restaurant.call为委托
委托可以封装多个方法
如果一个子类继承了父类(不管父类是抽象类还是接口类里面是否有子类里所有的变量)那么父类就能接受子类的变量 //例子:第五章材料中的milkinterface
//在类里声明:private readonly int aa;//readonly只能在构造函数中被赋值
//委托在new(放方法)后,方法里的传参就由委托(参数)完成,委托放在事件中后,委托中的参数(也就是方法中的参数)就由事件完成://调用:事件(参数)
//在事件定义时是没有参数的,//详见事件参数和定义事件   例子见下:
public class CoreOverHeatingEventArgs:EventArgs //必须继承EventArgs    //事件参数类(自定义)方法
 {
  private readonly int temperature;  //readonly 表示该字段在声明时赋值或在构造函数中赋值   在做它的属性时不用加readonly
  public CoreOverHeatingEventArgs(int temperature)
  {
   this.temperature=temperature;
  }
  public int GetTemperature()
  {
   return temperature;
  }
 }
public class CoreTempMonitor2
 {
  public delegate void StartPumpCallback(object sender,CoreOverHeatingEventArgs args);//定义委托   (谁触发的,事件参数所包含的数据//本例中此class是自定义的)
  public event StartPumpCallback CoreOverHeating;//定义事件时是不加()的
  public void SwitchOnAllPumps(int temp)
  {
   if(CoreOverHeating!=null)
   {
                if (temp > 2000)
                {
                    CoreOverHeating(this, new CoreOverHeatingEventArgs(temp));//()中的参数和定义委托时的参数是对应的this返回的是CoreTemMonitir2类
                }
   }
  }
 }
//例子详见第五章材料:“传递事件参数”
//当委托定义在类中的时候虽然是public调用时却不用new出的名字而用类名. 委托名  就和它是静态的一样


//////////////////////////////////////好例子
using System;

namespace 传递事件参数
{
 /// <summary>
 /// Class1 的摘要说明。
 /// </summary>
 //事件参数类
 public class CoreOverHeatingEventArgs:EventArgs
 {
  private readonly int temperature;  //readonly 表示该字段在声明时赋值或在构造函数中赋值
  public CoreOverHeatingEventArgs(int temperature)
  {
   this.temperature=temperature;
  }
  public int GetTemperature()
  {
   return temperature;
  }
 }
 public class ElectricPumpDriver
 {
  public void StartElectricPumpRunning(object sender,CoreOverHeatingEventArgs args)
  {
   Console.WriteLine("电子泵启动了");
   int currentTemperature=args.GetTemperature();
   Console.WriteLine("当前温度是:{0}",currentTemperature);
  }
 }
 public class PneumaticPumpDriver
 {
  public void SwitchOn(object sender,CoreOverHeatingEventArgs args)
  {
   //Console.WriteLine(sender.ToString());
   Console.WriteLine("气压泵启动了");
   int currentTemperature=args.GetTemperature();
   Console.WriteLine("当前温度是:{0}",currentTemperature);
  }
 }
 public class CoreTempMonitor2
 {
  public delegate void StartPumpCallback(object sender,CoreOverHeatingEventArgs args);
  public event StartPumpCallback CoreOverHeating;
  public void SwitchOnAllPumps(int temp)
  {
   if(CoreOverHeating!=null)
   {
                if (temp > 2000)
                {
                    CoreOverHeating(this, new CoreOverHeatingEventArgs(temp));
                }
   }
  }
 }
 class ExampleOfUse
 {
  public static void Main()
  {
   ElectricPumpDriver ed1=new ElectricPumpDriver();
   PneumaticPumpDriver pd1=new PneumaticPumpDriver();
   CoreTempMonitor2 ctm=new CoreTempMonitor2();
   ctm.CoreOverHeating+=new CoreTempMonitor2.StartPumpCallback(ed1.StartElectricPumpRunning);
   ctm.CoreOverHeating+=new CoreTempMonitor2.StartPumpCallback(pd1.SwitchOn);
            Console.WriteLine("当前温度是?");
            int temp = Convert.ToInt32(Console.ReadLine());
            ctm.SwitchOnAllPumps(temp);
  }
 }
}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 


                                         C#高级编程    第六章   对象序列化 /**/←→↑↓

//序列化:序列化就是将原来存在于内存中的对象转化成一个线性字节序列,并保存到硬盘里

//反序列化:反序列化就是把一个序列化了的对象回复到它在内存中的模样让程序使用


          序列化         网络传送                      反序列化(把字节流转换成对象)
     文件→→→→字节流→→→→→→(到达目标服务器)→→→→→→→→→→→→→→→→→→对象

 

//应用背景

分布式应用程序
{
 逻辑分布    AppDomain   ← 逻辑式应用程序域

 物理分布    服务器的地理位置不在一起
}

 


//序列化方法
{
 BinaryFormatter  : BinaryFormatter 类型使用紧凑的二进制格式将对象图序列化为一个流 /*命名空间:System.Runtime.Serialization.Formatters.Binary*/。   Formatter: 格式制做者, 做格式的人; 用来准备磁盘或硬盘以便使用的工具 (计算机用语) //  serialization: n.  连载长篇

 SoapFormatter    :将对象图表示为一个SOAP消息, /*命名空间:System.Runtime.Serialization.Formatters.Soap     引用时在引用图标上点添加*/  (SOAP 是一个基于XML的用于应用程序之间通信数据编码的传输协议 能和HTTP配合使用) 它生成的是一个XML文件
 /*SOAP: Simple Object Access Protocol    简单对象访问协议*/

 XMLSerializer :序列化为XML文档 /*命名空间:System.Xml.Serialization*/
 /*XML  : 是一种用户自定义的扩展性标记语言*/
}

 

//关于[Serializable] 和 [NonSerialized]
{
 [Serializable] : 希望被序列化就将此特征加到相应的类的上面

 [NonSerialized] : 不希望被序列化就将此特征加在方法或属性的上面

 //注意:
 {
  1、派生类:子类要是被标示上序列化特征,则父类也要标示上序列化特征
 
  2、公有字段、属性、私有字段: BinaryFormatter公有字段、属性、私有字段都能被序列化;  SoapFormatter 和 XMLSerializer只能序列化公有的字段和属性
 }
}

 
//各类方法
{
  BinaryFormatter
 {
     /*序列化*/:
     using System.Runtime.Serialization.Formatters.Binary;
     using System.IO; 

     /*在相应的类上面加上[Serializable] 在不想序列化的方法或属性上面加上[NonSerialized]*/
      /*在Main下*/
     /*将相应的类初始化了 ,把类中需要赋值的属性赋值了,该传值的传值*/

     BinaryFormatter formater = new BinaryFormatter();
                              ↑
                             名字自己起

     FileStream fs = new FileStream("Car.dat", FileMode.Create, FileAccess.Write, FileShare.None);
                       ↑                       ↑                                ↑              ↑
                      名字自己起    序列化后文件的名字 /                      文件的访问方式   是否能共享
                                    *注意扩展名(不用一定是.dat的,另外两种的扩展名是定死的)*/           

     formater.Serialize(fs, car); /*Serialize(文件流,对象)*/
            fs.close();             ↑
                                    相应的类名

 

 

 

    /*反序列化*/:
    using System.Runtime.Serialization.Formatters.Binary;
           using System.IO;
           using System.Runtime.Serialization;  /*能出[OptionalField]*/

    /*建立一个和序列化时结构一样的类 假设要反序列化的文件经历过变动/*第一次序列化(用的1.0版本)完成后在原类的基础上加了两个新的参数public int BeepFreq;public string ConsoleTitle; (加参数时用的2.0的版本)*/*/
    如果遇到加参数的情况,在建立新的接收类时在新的参数(public int BeepFreq;public string ConsoleTitle;)上面加上[OptionalField]

    /*在main下*/

     UserPrefs up;
                 ↑
          类名   设置一个空的类  用于接收反序列化的类
            FileStream fs = new FileStream("C:\\user.dat",FileMode.Open,FileAccess.ReadWrite,FileShare.None);
                                                 ↑
                                                要反序列化的文件的路径
            BinaryFormatter formater = new BinaryFormatter();

            up = (UserPrefs)formater.Deserialize(fs);
            ↑                       ↑
            开始接受               调用BinaryFormatter的Deserialize方法()中放的是读出的文件流,因为读出来的文件是Object类型的,所以需要强制转换成接受类的类型
            fs.Close();

            Console.WriteLine(up.objVersion + " " + up.BackgroundColor.ToString() + " " + up.ForegroundColor.ToString());
        ↑
                                                          将反序列化后的文件进行输出
 }

 

 

 

 

 

  XmlSerializer
 {
  using System.Xml.Serialization;
  using System.IO;

  /*在类的构造函数中必须有一个无参数的构造函数*/
  /*想把下面类的名字序列化为根节点,并带有名称空间,就在相应的类上面加上[Serializable,XmlRoot(Namespace="Http://www.btrj.cn")]*/          [Serializable,XmlRoot(Namespace="http://www.btrj.cn")] :把下面类的名字序列化为根节点,并带有名称空间   /*不加[Serializable,XmlRoot(Namespace="http://www.btrj.cn")]就把下面标记成根节点下的子节点*/
  /*想把类中的成员变量序列化成为根节点下的属性,就在相应的成员变量上面加上[XmlAttribute]*/

      /*在Main下*/
         /*将相应的类初始化了 ,把类中需要赋值的属性赋值了,该传值的传值*/

  XmlSerializer xmls = new XmlSerializer(typeof(student));
                                ↑                             ↑
                               名字自己起                    student为相应的类的名字,用typeof获得类的类型

                FileStream fs = new FileStream("student.xml",FileMode.Create);
                           ↑                        ↑
                        名字自己起       序列化后文件的名字 /*注意扩展名*/
                xmls.Serialize(fs,s);
                                  ↑
                                 相应的类的名字/*在这里是student类 new出的名字*/

                fs.Close();
                    ↑
                  关闭文件流


       /*xml文件*/
   {
                    <?xml version="1.0"?>
根节点没加[Serializable,XmlRoot(Namespace="Http://www.btrj.cn")]→   <student xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
                                           <studentId>101</studentId>
                                           <studentName>qinweilong</studentName>
                                         </student>

 

 

             <?xml version="1.0"?>
根节点加了[Serializable,XmlRoot(Namespace="Http://www.btrj.cn")]→   <student1 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" studentId1="102" studentName1="liwei" xmlns="Http://www.btrj.cn" />
   }

 

 

 

 


 /*反序列化*/  
            List<studentInfo> myStuInfo = new List<studentInfo>();
                                  ↑
                              建立一个对象和存储文件中的类型一样,用来接收
            using (FileStream myFs = new FileStream("data.xml", FileMode.Open))    /*Using(){} 用法见“扩展”*/
            {
                XmlSerializer myFxml = new XmlSerializer(typeof(List<studentInfo>));
                myStuInfo = (List<studentInfo>)myFxml.Deserialize(myFs);
            }

            foreach (studentInfo myi in myStuInfo)
            {
                this.lstStuInfo.Items.Add("学员编号:" + myi.StuID + "学员姓名:" + myi.StuName + "学员性别:" + myi.StuSex + "学员班级:" + myi.StuClass);
            }

 

 

 


 }

 

 


 soapFormatter:例子见流程控制

 

}


    
           
          
    

 


//类型保真
{
 使用BinaryFormatter类型时,不仅仅是将对象图中的字段数据持久化,而且也持久化每个类型的完整修饰名称和定义程序集的完整名称   保真率最高

 SoapFormatter 和 XMLSerializer :  XML数据表现形式具有终端开放性,持久化的对象图可以被任意操作系统(Windows XP、Mac OS x 和各种Unix系统)、应用程序框架(.Net、J2EE、COM等)或编程语言使用
}

 


// as 类型转换
 

 

//三者的不同之处
{
//SoapFormatter 生成 .soap 文件,不能序列化集合

//SoapFormatter 和 BinaryFormatter 继承 IFormatter  IRemotingFormatting 两个接口,也就是说可以用这两个接口接受变量

//XMLSerializer {
    1、不继承IFormatter  IRemotingFormatting 两个接口
    2、生成的是纯XML文件
    3、序列化时需要指定类型    /*typeof(Student)    student 为类名*/
    4、没[Serializable] 和 [NonSerialized]
  }
}

 

//XML可以用泛型集合 :  (typeof(list<...>))  //获得泛型类的类型
                                     ↑
                                    类型、
 //例子 :XmlSerializer myXml = new XmlSerializer(typeof(List<studentInfo>));

 

//控制XML输出

    


//自定义序列化过程  SerializationInfo MsDn

 

 


//自动调用:
{
 [OnSerializing] : 正在序列化时自动调用
 [OnSeialized]   : 序列化完成时自动调用
 [OnDeserializing] :正在反序列化时自动调用
 [OnDeserialized]: 反序列化完成时自动调用


 /*例子*/
 using System;
 using System.Collections.Generic;
 using System.Text;
 using System.Runtime.Serialization;
 using System.Runtime.Serialization.Formatters.Soap;    /*引用时在引用图标上点添加*/
 using System.IO;

 namespace private_gouzaohanshu
{
 //[Serializable]
     //public class MyStringData : ISerializable   //ISerializable : 允许对象控制其自己的序列化和反序列化过程
     //{
     //    public string dataItemOne, dataItemTwo;
     //    public MyStringData() { }
     //    private MyStringData(SerializationInfo si, StreamingContext ctx)    //私有构造函数:不希望别人构造实例,只能自己构造自己
     //    {
                                                 将"First_Item"对应的值取出
                                                   ↓
     //        dataItemOne = si.GetString("First_Item").ToLower();
     //        dataItemTwo = si.GetString("Second_Item").ToLower();
     //    }
                                 存储将对象序列化或反序列化所需的全部数据      没什么用
                                                          ↓                   ↓
     //    void ISerializable.GetObjectData(SerializationInfo info, StreamingContext ctx)   //人为干预 ISerializable有个唯一的方法:GetObjectData 人为干预时在class被序列化时自动调用
     //    {
                                 添加类似一个键值对似的东西,"First_Item"作为dataItemOne.ToUpper()的一个标记
                                    ↓
     //        info.AddValue("First_Item", dataItemOne.ToUpper());
     //        info.AddValue("Second_Item", dataItemTwo.ToUpper());
     //    }
     //}

     [Serializable]
     public class datastringitem
     {
         public string dataitem1;
         public string dataitem2;              固定用法,名字随便起,记住就行
         [OnSerializing]                           ↓
         internal void Onserializing(StreamingContext sContext)  //internal 关键字是类型和类型成员的访问修饰符。只有在同一程序集的文件中,内部类型或成员才是可访问的
         {                                                       //StreamingContext :描述给定的序列化流的源和目标,并提供一个由调用方定义的附加上下文。
              dataitem1 = dataitem1.ToUpper();
              dataitem2 = dataitem2.ToUpper();
         }
         [OnDeserialized]
         internal void OnDeserialized(StreamingContext sContext)
         {
              dataitem1 = dataitem1.ToLower();
              dataitem2 = dataitem2.ToLower();
         }

     }
     class Program
     {
         static void Main(string[] args)
         {
              datastringitem dat = new datastringitem();
              dat.dataitem1 = "qinweilong";
              dat.dataitem2 = "qwe";
              SoapFormatter sf = new SoapFormatter();
              FileStream fs = new FileStream("mysoap.soap",FileMode.Create);
              sf.Serialize(fs,dat);   //程序走到此处时会自动调用[OnSerializing] 和 [OnSerialized] 特征下的方法//////在被注释的程序中会调用ISerializable.GetObjectData(SerializationInfo info, StreamingContext ctx)方法
              fs.Close();
              Console.WriteLine("序列化完成");

              Console.WriteLine("开始反序列化");
              datastringitem data111;    /*私有构造函数:  现在没有实例化,下面的“类型转换时”相当于初始化构造函数     (datastringitem)sf111.Deserialize(fs111) ,又是sf111它本身自己点出的方法,相当于“自己调用自己”*/
              SoapFormatter sf111 = new SoapFormatter();
              FileStream fs111 = new FileStream("mysoap.soap", FileMode.Open);
              data111 = (datastringitem)sf111.Deserialize(fs111);  //程序走到此处时会自动调用 [OnDeSerializing] 和 [OnDeSerialized] 特征下的方法///////在被注释的程序中会调用私有构造函数
              fs111.Close();
              Console.WriteLine(data111.dataitem1.ToString());
              Console.WriteLine(data111.dataitem2.ToString());
         }
     }
}

}

 

 

 

//扩展:
{
 using()  /*用法 : 在()中实例化的对象在出了{}后会自动被销毁*/
 {
 }

    /*例子*/
          using (FileStream myFs = new FileStream("data.soap", FileMode.Create))
            {
                //使用SoapFormatter类对象调用序列化方法
                //在使用SoapFormatter类时需要添加引用。
                SoapFormatter mySoap = new SoapFormatter();
                //注意:SoapFormatter不能序列化集合
                mySoap.Serialize(myFs, mya);
                myFs.Close();
            }
}

 

 

 

 


 

posted on 2010-03-09 09:16  秦威龙  阅读(667)  评论(0编辑  收藏  举报