反射&特性&序列化

先回忆一下:
      两次编译一次运行:1)第一次将源代码转换为中间语言(exe、dll内部都存放的中间语言)
                                           2)第二次将中间语言转换成机器语言
1、反射:编程的读取与类型相关联的元数据的行为,给定一个路径通过特定方法得到一个类中所有的成员,这样比较方便,不必添加引用就可以动态获取内部成员,所属命名空间System.Reflection
使用反射的步骤:
       1)利用Assembly的LoadForm方法引用一个要反射的程序集,将路径引用进来
          例:Assembly assembly=Assembly.LoadFrom (@"C:\Users\ling890316\Desktop\暑期实训\ManageMinpian\ConsoleApplication1\bin\Debug\ConsoleApplication1.exe");
 
2)为被反射的程序集创建实例
          例:object obj=assembly.CreateInstance(" Client.Program");//此时就会调用一次反射类的无参构造函数

       3)可以反射不同类型的成员(方法、属性、构造函数、字段、类型等等)
反射方法:
            MethodInfo mi= obj.GetType().GetMethod("Fangfa",BindingFlags.NonPublic |BindingFlags.Instance  );//将方法名引进来,反射私有的方法
            //MethodInfo mi = obj.GetType().GetMethod("Fangfa");//反射公有的方法
            mi.Invoke(obj,null);//调用被反射的成员或类型的方法
  反射属性:
           PropertyInfo pi=  obj.GetType().GetProperty("Str");//反射程序集的属性Str
           pi.SetValue(obj,29,null);//为属性Str设置值,调用属性中的set访问器
           Console.WriteLine ( pi.GetValue(obj, null));//获取属性中的值,调用属性的get访问器,并打印出来
   反射所有的成员:            
            object[] member = obj.GetType().GetMembers(BindingFlags.NonPublic | BindingFlags.Instance);//获取被反射类的所有私有成员
            //最终用一个object类型的数组保存
            foreach (object a in member)
             {
                Console.WriteLine(a);
             }//将所有反射到的私有成员显示出来
          
   反射构造函数(有参或无参):               
             1)反射有参构造函数
            Type[] types = new Type[] {typeof (string )};
            ConstructorInfo ci= obj.GetType().GetConstructor(types);//反射有参的构造函数,该方法必须接收一个Type类型的数组
            //数组中存放的是string类型的值然后转化成Type类型
            object [] obj1=new  object []{"7373"};//定义一个object类型的数组,该数组保存一个值是string类型的,与有参构造函数
            //的参数匹配
            ci.Invoke(obj,obj1);//在实现时就会调用有参构造函数
2)反射无参构造函数
            Type[] types = new Type[] {};
            ConstructorInfo ci= obj.GetType().GetConstructor(types);//反射无参的构造函数,该方法必须接收一个Type类型的数组
            //要想使得可以反射无参构造函数,可以在types数组中不存放值           
            ci.Invoke(null);//直接就可以调用无参的构造函数了,这里同ci.Invoke(obj,null);是一样的,都调用无参构造函数
反射字段:
            FieldInfo fi= obj.GetType().GetField("ziduan",BindingFlags.NonPublic |BindingFlags.Instance );           
            Console.WriteLine ( fi.GetValue(obj));
反射索引器:
这个地方我自己还没有做出来,回头补上!
           
注意:只有属于命名空间的类型或该类型的成员才会反射回来,至于被反射的的命名空间使用的成员或类型无法反射得到
2、特性(属性):Attribute非property(类的成员),它不是类的成员,只是附属于类的,属性提供功能强大的方法以将声明信息与C#代码(类型、方法、属性等)相关联。
        属性与程序实体关联后,即可在运行时使用名为“反射”的技术查询属性。
特性以两种形式出现:
      1) 一种是在公共语言运行库 (CLR) 中定义的属性(微软定义好的)。
       2)另一种是可以创建的用于向代码中添加附加信息的自定义属性。此信息可在以后以编程方式检索。
特性具有以下特点:
       1)属性可向程序中添加元数据。元数据是嵌入程序中的信息,如编译器指令或数据描述。
       2)程序可以使用反射检查自己的元数据。
      3) 通常使用属性与 COM 交互。
自定义特性:
      特性类实例化时需要放在括号“[ ]”中,语法:
      [attributeClass(定位参数1,… 命名参数1,…)]
自定义特性有两种类型:
          1)定位参数(相当于实例类的构造函数)
          2)命名参数(相当于实例类的属性,可以赋值也可以不赋值(默认值))
例子:以下就是使用Windows的一个特性实现在控制台弹出窗口
    
        [DllImportAttribute("user32.dll", EntryPoint = "MessageBoxW")]//自定义一个特性,"user32.dll"是定位参数
              //EntryPoint = "MessageBoxW"是命名参数
        public static extern int MessageBoxW([InAttribute()] System.IntPtr hWnd,
            [InAttribute()] [MarshalAsAttribute(UnmanagedType.LPWStr)] string lpText,
            [InAttribute()] [MarshalAsAttribute(UnmanagedType.LPWStr)] string lpCaption,
            uint uType);
static void Main(string[] args)
        {
            Console.WriteLine(MessageBoxW(IntPtr.Zero, "确定吗?", "提示", 1));
        }
小练习:讲这个自定义特性的时候老师用了一个很形象的比喻的比喻就是猪与虱子的关系,虱子是附加在猪身上的,不是猪的一部分,这里的虱子就相当于一个自定义的特性,下面我们来看看实现了的这个小程序吧!
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
namespace ConsoleApplication4
{
    class Program
    {
        static void Main(string[] args)
        {
            zhu zu = new zhu();//实例化猪这个类的对象
            foreach (object obj in zu.GetType().GetCustomAttributes(true))//用反射的方法得到zu这个类的特性, GetCustomAttributes(true)此处必须填true,至于什么原因我还没弄明白,记住吧!!!
                //得到了特性,由于它返回的是一个object类型的数组,所以先遍历出来
            {
                shiziAttribute shizi = obj as shiziAttribute;//将得到的object类型的特性先转换成shiziAttribute 类型
                Console.WriteLine("名称: {0} 大小: {1}",shizi.Name,shizi.Size  );//打印输出该特性的属性值
            }
           
        }
}
    [AttributeUsage(AttributeTargets.Class,AllowMultiple=true,Inherited=true)]//定义一个特性,它针对类Class建立的,
    //AllowMultiple=true表示它允许有多个实例,Inherited=true表示其可以被其他类继承
    class shiziAttribute : Attribute
    {
        string name;
        public shiziAttribute(string name)
        {
            this.name= name;
        }//为该特性的类定义一个有参构造函数,接收一个string类型的参数,在内部设置其值
        public string Name
        {
            get
            {
                return name;
            }
        }//属性Name,只有可读属性
        double size;
        public double Size
        {
            get
            {
                return size;
            }
            set
            {
                size = value;
            }
        }//属性Size,可读可写
    }
    [shizi("大虱子", Size = 2.3)]//特性的使用方法,"大虱子"是特性定义中的定位参数(相当于实例类中的构造函数);
    // Size = 2.3是特性定义中的命名参数(相当于实例类中的属性)
    [shizi("小虱子", Size = 1.0)]//因为在定义特性类的时候设置了AllowMultiple=true属性,所以允许有多个特性的实例
        //存在,虱子的特性附加在猪上,一定要分清楚该特性不是猪的一部分,不能通过猪这个类的实例化对象直接访问
    class zhu
    {
    }
}
练习:利用反射的原理实现操作数据库数据的功能
思路总结:这个由于最近要做项目,所以在这里先空出来,以后补上啦!
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            //第三步:反身特性类信息,使用反射的方法,反射回类Blog所有的特性
            Blog blog = new Blog();
            blog.Author = "桂素伟";
            blog.Title = "技术有你,共同前行";
            blog.CreateDate = DateTime.Parse("2007-9-1");
            blog.ID = 10;
//delete 表名 where 主键字段名=值
Console.WriteLine(GetDelete(blog));
Article article = new Article();
            article.Title = "c#学习方法";
            article.Type = "C#";
            article.Content = "每天学习18个小时";
            article.ID = 200;

            Console.WriteLine(GetUpdate(article));
        }
        //update 表 set 字段1=值1,字段2=值2 where 主键字段=值
        static string GetUpdate(IEntity entity)
        {
            object[] objarr = entity.GetType().GetCustomAttributes(true);
            if (objarr.Length == 0)
            {
                return "";
            }
            else
            {
                foreach (object o in objarr)
                {
                    if (o is TableAttribute)
                    {
                        TableAttribute ta = o as TableAttribute;//将反射得到的特性(object类型)转换成TableAttribute格式
                        string tablename = ta.TableName;
string fieldname = "";
                        string fieldvalue = "";
                        Dictionary<string, string> pros = new Dictionary<string, string>();
                        foreach (PropertyInfo pi in entity.GetType().GetProperties())//获取blog这个对象的全部的属性,比如id、zuozhe、biaoti、shijian
                        {
object[] proarr = pi.GetCustomAttributes(true);//反射得到blog属性的特性,将其保存在一个object类型的数组中
                            if (proarr.Length == 0)
                            {
                                continue;
                            }//如果数组为空,表示blog的当前循环中的这个属性没有附加特性,返回属性(返回foreach (PropertyInfo pi in entity.GetType().GetProperties()) 继续循环
                            else
                            {
                                foreach (object ob in proarr)//遍历blog的当前属性的特性
                                {
                                    if (ob is FieldAttribute)//判断blog的当前属性是否附加了特性
                                    {
                                        FieldAttribute fa = ob as FieldAttribute;//将反射得到的属性的特性(object类型)转换成FieldAttribute格式
                                        if (fa.IsPrimaryKey)//判断当前的特性是否是主键
                                        {
                                            fieldname = fa.FieldName;//判断如果是主键,则获取该属性特性的名称赋值给外部定义好的fieldname中
                                          
                                            fieldvalue = pi.GetValue(entity, null).ToString();//获取该属性(为主键)的值(该属性对应的特性)将其保存在外部定好的fieldvalue中
                                        }
                                        else
                                        {
                                            pros.Add(fa.FieldName, pi.GetValue(entity, null).ToString());//将不为主键的其他的属性的特性和获取到的属性对应的值保存在定义好的泛型哈希表中
                                        }
                                    }//表示blog的属性附加有特性,那么就将得到的特性(保存在object类型的数组o中)转换为FieldAttribute 先判断,如果该特性的IsPrimary为真,就将该特性的名称保存在primaryname中,将该特性的值保存在 primaryvalue中,供后来使用
                                }
                            }
                        }
if (pros.Count == 0)
                        {
                            return "";
                        }//判断,如果哈希表中没有元素,即没有检索到属性的特性和对应的属性的值
if (fieldname == "" || fieldvalue == "")
                        {
                            return "";
                        }//判断如果没有主键或者主键为空,就返回空值
string sql = "update " + tablename + " set ";
                        foreach (string key in pros.Keys)
                        {
                            sql += key + "='" + pros[key] + "',";
                        }
                        sql = sql.TrimEnd(',') + " where " + fieldname + "=" + fieldvalue;
                        return sql;
                    }
                    else
                    {
                        return "";
                    }
                }
                return "";
            }

        }
       
        static string GetDelete(IEntity entity)
        {
            TableAttribute ta = entity.GetType().GetCustomAttributes(true)[0] as TableAttribute;
            string tablename = ta.TableName;
string fieldname = "";
            string fieldvalue = "";
            foreach (PropertyInfo pi in entity.GetType().GetProperties())
            {
                FieldAttribute fa = pi.GetCustomAttributes(true)[0] as FieldAttribute;
                if (fa.IsPrimaryKey)
                {
                    fieldname = fa.FieldName;
                    fieldvalue = pi.GetValue(entity, null).ToString();
                }
            }
string sql = "delete " + tablename + " where " + fieldname + "=" + fieldvalue;
            return sql;
}
    }
    //第一步:定义特性类
    /// <summary>
    /// 定义一个特性类,用来保存表名
    /// </summary>
    [AttributeUsage(AttributeTargets.Class)]
    class TableAttribute : Attribute
    {
        string tablename;
        public TableAttribute(string tablename)
        {
            this.tablename = tablename;
        }//为特性建立一个定位参数,该参数表示表的名称,必须有值
        public string TableName
        {
            get
            {
                return tablename;
            }
        }//为name定义一个只读属性,使得它在外部可以被访问的到
    }
    /// <summary>
    /// 定义一个特性类,用来指向table表中不同的字段
    /// </summary>
    [AttributeUsage(AttributeTargets.Property)]
    class FieldAttribute : Attribute
    {
        string fieldname;
        public FieldAttribute(string fieldname)
        {
            this.fieldname = fieldname;
        }//为特性类定义一个定位参数,用来保存唯一且必须存在的值,表示表中的字段名称
        public string FieldName
        {
            get
            {
                return fieldname;
            }
        }//为fieldname定义一个属性,使得它在外部可以被访问的到
public bool IsPrimaryKey
        {
            get;
            set;
        }//表示是否为表中的主键
    }
    interface IEntity
    {
    }
    //第二步:使用特性类
    [Table("blogs")]
    class Blog : IEntity
    {
        [Field("ID", IsPrimaryKey = true)]//在Blog这个类里定义了四个字段,对应四个属性,这四个字段分别是博客编号、博客作者、博客主题、博客的创建时间,分别对这四个属性使用外部定义好的特性,例如第一个属性表示博客编号的属性ID,它引用了外部的特性,映射在blogs表中其存储为ID(特性定义中的定位参数)同时在特性中定义了IsPrimaryKey=true,表示该字段是blogs表中的主键,通俗地说要想使该类的属性都可以存储对应blogs表中的字段,必须对该表所有的属性都套用外部定义好针对属性的特性FieldAttribute
        public int ID
        {
            get;
            set;
        }
        [Field("ZuoZhe")]
        public string Author
        {
            get;
            set;
        }
        [Field("BiaoTi")]
        public string Title
        {
            get;
            set;
        }
        [Field("ShiJian")]
        public DateTime CreateDate
        {
            get;
            set;
        }
    }
   // [Table("articles")]
    class Article : IEntity
    {
        [Field("ID", IsPrimaryKey = true)]
        public int ID
        {
            get;
            set;
        }//博客编号,主键
        [Field("TM")]
        public string Title
        {
            get;
            set;
        }//博客主题
        [Field("NR")]
        public string Content
        {
            get;
            set;
        }//博客内容
        [Field("LX")]
        public string Type
        {
            get;
            set;
        }//博客类型
public int T
        {
            get;
            set;
        }//这个属性没有附加特性
}
}

3、序列化:将对象状态转换为可保持(保存)或传输的形式的过程。序列化的补集是反序列化,后者将流转换为对象,这两个过程一起保证数据易于存储和传输,本质是存储字段(数据),中间的方法等其他的都不去序列化。
序列化的两种方式:
       1)序列化二进制(占用空间小)
       2)序列化XML(格式很好,但文件较大)
序列化的命名空间
           1)二进制序列化需要的命名空间
              using System.Runtime.Serialization;
              using System.Runtime.Serialization.Formatters.Binary;
2)XML序列化需要的命名空间
              using System.Runtime.Serialization.Formatters.Soap;(需要添加引用)
选择序列化:
    [Serializable]//加了这个标志后表示该成员可以被序列化
    public class Person
    {        
       [NonSerialized]
        public  int age;//这个age将不会序列化
        public bool Sex
        {  get;  set;  }
    }
序列化的小练习:  
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.IO;
using System.Threading;
using System.Collections ;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters .Binary ;
using System.Runtime.Serialization.Formatters.Soap;
namespace Client
{
    class Program
    {
static void Main(string[] args)
        {
            Person xihong = new Person();
            xihong.Name = "小红";
            xihong.Age = "21";
序列化为二进制文件
            //IFormatter formatter = new BinaryFormatter();//格式化器
            //Stream stream = new FileStream ("D:/a.bin",FileMode.Create ,FileAccess.Write );
            //formatter.Serialize(stream,xihong );
            //stream.Close();
序列化为XML文件
            //IFormatter formatter1 = new SoapFormatter();
            //Stream stream1 = new FileStream("D:/a.xml", FileMode.Create, FileAccess.Write);
            //formatter1.Serialize(stream1, xihong);
            //stream1.Close();
//反序列化
            IFormatter formatter = new BinaryFormatter();
            Stream stream = new FileStream("D:/a.bin",FileMode.Open ,FileAccess.Read );
            Person xi = (Person)formatter.Deserialize(stream);//将二进制文件中的流反序列化出来转换成XiHong 这个类类型,并保存在一个新的对象xi中,注:这个新对象xi同原来的对象xihong只是数据一样,本质是不同的
            Console.WriteLine(xi.Name );
            Console.WriteLine(xi.Age );
Console.WriteLine(xi.Equals(xihong));//此时是返回false,因为这个新对象xi同原来的对象xihong只是数据一样,本质是不同的
        }      
      
    }
    [Serializable ]
    class Person
    {
        public string Name
        {
            get;
            set;
        }
      
        public string Age
        {
            get;
            set;
        }
    }

 

转载于:https://blog.51cto.com/fayling/626665

.NET Framework- 反射特性序列化(Day4)相关推荐

  1. Django restful Framework 之序列化与反序列化

    1. 首先在已建好的工程目录下新建app命名为snippets,并将snippets app以及rest_framework app加到工程目录的 INSTALLED_APPS 中去,具体如下: IN ...

  2. Rest Framework:序列化组件

    Django内置的serializers(把对象序列化成json字符串 from django.core import serializersdef test(request):book_list = ...

  3. CAF(C++ actor framework)(序列化之结构体,任意嵌套STL)(一)

    User-Defined Data Types in Messages(用户自定义类型) All user-defined types must be explicitly "announc ...

  4. 谈谈Django REST Framework(DRF)中的序列化器

    摘要 Django REST Framework(DRF)是一个强大的工具,可以帮助我们构建和处理RESTful API.其中的序列化器(Serializers)是其核心组件之一,它允许我们快速有效地 ...

  5. Django REST framework学习笔记

    文章目录 1. API接口开发 1.1 获取数据的接口 1.2 添加数据的接口 1.3 更新数据的接口 1.4 删除数据的接口 2. API字段的定制 2.1 别名字段 2.2 字段格式化 2.3 字 ...

  6. Django REST framework 理解

    Web应用模式 1 .前后端不分离:在前后端不分离的应用模式中,前端页面看到的效果都是由后端控制,由后端渲染页面或重定向,也就是后端需要控制前端的展示,前端与厚度那的耦合度很高. 这种应用模式比较合适 ...

  7. jsch 移动服务器上文件,jsch上传文件到服务器

    需求就是上传文件到服务器,服务器的存储地址由程序决定然后可以自动创建. 使用第三方:jsch JSch 是SSH2的一个纯Java实现.它允许你连接到一个sshd 服务器,使用端口转发,X11转发,文 ...

  8. 通过避免下列 10 个常见 ASP.NET 缺陷使网站平稳运行(转)

    本文将讨论: • 缓存和 Forms 身份验证 • 视图状态和会话状态 • 配置文件属性序列化 • 线程池饱和 • 模拟和设置配置文件 本文使用了下列技术: .NET Framework.ASP.NE ...

  9. 《果壳中的C# C# 5.0 权威指南》 (09-26章) - 学习笔记

    <果壳中的C# C# 5.0 权威指南> ========== ========== ========== [作者] (美) Joseph Albahari (美) Ben Albahar ...

最新文章

  1. Unity Fine Prued Tiled Light (FPTL)
  2. osx doc to html,macos – 在OSX上安装Git HTML帮助
  3. 搭建负载均衡器nginx_为什么要使用NGINX作为负载均衡器?
  4. java mongo数据去重复_java – MongoSpark保存重复的密钥错误E11000
  5. VUE 的使用,学会这些就足够了!| 原力计划
  6. python代码翻译器-Python编程学习 -- 用十几行代码实现一个翻译器
  7. 祛除光盘上的小划痕/光盘的工作原理/光盘的正确使用方法
  8. CCS10.2.0安装教程
  9. 单因素方差分析及其相关检验
  10. 如何去掉图片上的logo
  11. 装黑苹果的那些事儿(以ThinkpadE540为例)
  12. [转载]Html 特殊符号 让版权符号更美观_几何途行_新浪博客
  13. 视频资源网站采集-视频资源API采集教程
  14. Java--多线程之并发,并行,进程,线程(一)
  15. SpringBoot 2 访问 Neo4j 图数据库
  16. VBA中数组72变(随心所欲复制)
  17. Spark 3.x各模式部署 - Ubuntu
  18. 当兵的目标和计划_新兵下连时,一定要弄明白这三件事,对新兵及家长来说很有必要...
  19. 快速入门 Remix IDE
  20. 【院校信息】2021中国海洋大学计算机考研数据汇总

热门文章

  1. python补课费用_学习python阶段小总结
  2. matlab中(1 )什么意思,matlab中area(1)什么意?mat – 手机爱问
  3. matlab画扇区,NFCDemo NFC读写测试 ,自动读取每个扇区 块的值 matlab 238万源代码下载- www.pudn.com...
  4. Java设计模式(十九):解释器设计模式
  5. 现代操作系统: 第五章 输入/输出
  6. Twitter Heron 实时流处理系统简介
  7. 下列哪个是java的标识符_下列哪个不属于Java的正确标识符?A、publicB、sizeofC、cLAssD、_new...
  8. 【BZOJ】P2144 跳跳棋
  9. javascript 常用知识点
  10. T1330 最少步数(#Ⅱ- 8)(广度优先搜索)