本文是学习特性与反射的学习笔记,在介绍完特性和反射之后,会使用特性与反射实现一个简单的将DataTable转换为List的功能,水平有限,如有错误,还请大神不吝赐教。

1.      反射:什么是反射?反射就是在程序运行的过程中,动态的获取类的成员,并对他们进行操作。包括动态调用方法,动态获取,设置属性等。通过特性,也能是想IOC,AOP等功能。

2.      特性:特性只有在使用反射的时候才能发挥它最大的作用,通过反射获取到自定义的特性,再根据特性进行操作,例如在通过反射实现ORM的时候,如果一个熟悉设置了不需要ORM的特性,则可以忽略该属性。如果没有反射,那么可以把特性当做注释,它不会对代码的运行造成任何影响。但它和注释的区别在于,它会被编译进程序集,这样才能通过反射获取到这些特性。

3.      下面先演示反射的用法,反射常用的类有Assembly,Activator,Type这几个类

Assembly获取程序集应用,可以通过Load,LoadFile,LoadFrom这几个方法将dll文件加载进当前程序集。如果需要反射的类位于当前程序集,则可以不使用此类

Activator用于动态的创建一个类的实例,通过Assembly加载的程序集,可以获取到它内部的所有的Type,而Activator.Crea  teInstance方法可以为当前对象创建一个实例。(Assembly也有CreateInstance方法用于创建类的实例)。

Type表示一个类型,也可以通过typeof获取例如typeof(int)得到的就是int类型,然后Type对象有很多的方法可以获取对象的成员,包括字段,方法,属性等等对象内部的所有都可以通过Type获得。

下面是使用反射的示例

3.1、       添加一个新的类库,添加下面的代码,并生成为一个dll文件

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Threading.Tasks;

namespace RefleatorDll

{

/// <summary>

/// 此类用于反射获取到的对象的测试类

/// 通过反射获取的类,不需要是public的,即使是private的类也是可以获取到的

/// 类内部的所有成员,即使是private的,全部可以通过反射进行更改,但强烈不建议那样做,私有成员之所以为私有的,一定有必要的原因,

/// 对私有成员的修改可能对类的运行造成难以预料的影响

/// </summary>

public class CustomClass

{

//用于反射的字段,包括私有,公有,静态字段用于演示不同的字段如何修改

//下方的属性相同

private string _name = null;

public int _age = 0;

public static string _address = null;//静态字段不设置属性,如有必要也可以设置

public string Name { get { return _name; } set { _name = value; } }

public int Age { get { return _age; } set { _age = value; } }

//用于反射获取和调用类的方法

//只包括静态和公有方法私有方法的获取请参考私有字段的获取

//方法也包括有返回值与如返回值

//其他情况的方法,请举一反三去获取

public string GetName()

{

return _name;

}

public static void ShowAge(string name,int age)

{

Console.WriteLine($"{name}'s age is :" + age);

}

}

}

3.2、       在主程序中通过反射对此类进行操作

string path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "RefleatorDll.dll");

Assembly asm = Assembly.LoadFile(path);//加载程序集

//asm.GetType方法与GetTypes的区别在于,前者通过指点类型的名称获取指定的Type,后者会获取到当前程序集中的所有类

//类型名使用FullName

Type cs = asm.GetType("RefleatorDll.CustomClass");

//为当前Type创建一个实例

//此方法有很多的重载,可以结合实际情况选择使用哪一个重载

object obj = Activator.CreateInstance(cs);

//获取及修改私有的字段

//如果是通过New的到的对象,私有字段是不能获取及修改的,但是通过反射就可以,同理属性,方法也是一样

//BindingFlags用于设置指定类型的字段,包括私有的,公有的,静态的,继承的,非继承的,等类型

//下面的方法只获取公有的,静态的,非公有的,如果不知道则默认获取公有字段

FieldInfo[] fis = cs.GetFields(BindingFlags.Static|BindingFlags.NonPublic|BindingFlags.Public|BindingFlags.Instance);

FieldInfo fi = cs.GetField("_name", BindingFlags.Instance | BindingFlags.NonPublic);

//如果是实例字段,则需要将上面创建的obj传入,如果是静态字段则传入null即可

Console.WriteLine(fi.GetValue(obj).ToString());//显示当前值,当前显示为""

fi.SetValue(obj, "此坑已满");

Console.WriteLine(fi.GetValue(obj).ToString());//显示当前值,显示为设置的值

Console.WriteLine("方法执行完毕!");

Console.ReadKey();

显示结果为:

属性的操作与字段操作相同只是将FieldInfo换为PropertyInfo即可

下面演示方法的调用

创建对象的方法上面的实例已经有了,所以此处只附调用方法的代码

//带返回值的方法

//如果是重载方法的话,需要在参数2中指定需要使用的方法的参数对应的数量和类型

MethodInfo mis = cs.GetMethod("GetName", BindingFlags.Instance|BindingFlags.Public);

//参数2指定传入的参数数组如果当前执行的方法没有参数则传入null即可

object returnValue = mis.Invoke(obj, null);

Console.WriteLine(returnValue);//由于上面设置了_name的值,所以此处显示设置的值

//静态方法

MethodInfo misS = cs.GetMethod("ShowAge", BindingFlags.Static | BindingFlags.Public);

misS.Invoke(null, new object[] { "此坑已满", 26 });

执行结果

以上就是反射的简单使用方法,下面是反射结合特性的方法

1.      定义一个自定义的特性,.Net框架自带很多的特性,如果写过WCF或者MVC就会有深刻的体验,比[Required],[HttpGet]等

//AttributeUsage特性用于自定义特性,它用于设置特性的作用范围

//例如此特性就只能用在方法上,已经特性是否可以多次使用,是否继承父类的特性等

//自定义特性约定为{name}+Attribute,当然也可以不加Attribute

//区别在于加后在使用时可以不加Attribute否则就必须输入特性的全名

//例如ShowAttribute使用时只需要使用[Show]即可

//自定义特性必须继承自Attribute类

[AttributeUsage(AttributeTargets.Method)]

public class ShowAttribute : Attribute

{

public ShowAttribute(string methodName)

{

Console.WriteLine("您通过特性找到了方法:" + methodName);

}

}

2.定义一个类并添加此特性

//此类用于演示ShowAttribute特性

public class ShowAttTest

{

[Show("ShowMethod")]

public void ShowMethod()

{

//因为此方法只是用来测试特性的功能的,所以不做具体业务处理,直接返回

return;

}

}

3.通过反射调用此方法

//反射特性测试,用于测试静态方法获取自定义特性与使用实例方法获取自定义特性是否执行特性内部方法的差别

Type t = typeof(ShowAttTest);

MethodInfo mi = t.GetMethod("ShowMethod");

//通过反射的实例方法获取自定义特性,此方法会造成特性的代码被执行

mi.GetCustomAttribute(typeof(ShowAttribute));

//通过静态方法获取自定义特性,此方法不会执行特性的代码

//CustomAttributeData.GetCustomAttributes(mi);

运行结果:

以上就是反射和特性的基础知识了,下面使用反射和特性实现一个简单的

将DataTable转换为实体类

获取到的DataTable的数据

转换后的数据请自行调试

示例源码

1.      自定义的特性

//此特性仅用于忽略字段标识,同时设置为只能为属性添加

[AttributeUsage(AttributeTargets.Property)]

public class IngoreAttribute:Attribute

{

}

//此特性用于设置当前属性对应的数据库字段的名称

[AttributeUsage(AttributeTargets.Property)]

public class ColumnNameAttribute : Attribute

{

public string Name;//用于保存字段的名称

public ColumnNameAttribute(string name)

{

Name = name;

}

}

2.      自定义实体

//此类模拟一个实体类

public class CustomEntity

{

public int ID { get; set; }

public string Name { get; set; }

[ColumnName("TelePhone")]//设置Phone的字段为TelePhone

public string Phone { get; set; }

public string Email { get; set; }

[Ingore]//忽略此字段,不从DataTable中获取

public string IngoreTest { get; set; }

}

3.      转换类

//此类用于转换DataTable到List

public class ConvertToList

{

/// <summary>

/// 实际转换的方法--约束泛型参数T只能是应用类型,同时必须包含一个无参构造函数

/// </summary>

/// <typeparam name="T"></typeparam>

/// <returns></returns>

public List<T> GetList<T>(DataTable dataTable) where T : class, new()

{

List<T> list = new List<T>();

Type type = typeof(T);

//获取当前的实体的所有公共属性

PropertyInfo[] pis = type.GetProperties(BindingFlags.Public | BindingFlags.Instance);

foreach(DataRow row in dataTable.Rows)

{

T t = new T();//创建一个实例

foreach (var item in pis)

{

//如果属性设置了Ingore特性,则直接跳过此属性

Attribute ingore = item.GetCustomAttribute(typeof(IngoreAttribute));

if (ingore != null)

{

continue;

}

string fieldName = item.Name;//取出属性的默认名字当做字段默认名

ColumnNameAttribute columnName = item.GetCustomAttribute(typeof(ColumnNameAttribute)) as ColumnNameAttribute;

//如果当前属性添加了ColumnName特性,则设置字段名为Name

if (columnName != null)

{

fieldName = columnName.Name;

}

//由于演示的关系此处只添加了int类型的转换

if (item.PropertyType == typeof(int))

{

item.SetValue(t, Convert.ToInt16(row[fieldName].ToString()));//为当前属性赋值*注意此处可能存在装箱拆箱的问题

}

else

{

item.SetValue(t, row[fieldName]);

}

}

list.Add(t);

}

return list;

}

}

4.      测试代码

//ConvertToList测试

//此处模拟从数据库获取的数据,实际项目中请从真实的数据库获取数据

DataTable dt = new DataTable();

dt.Columns.Add("ID");

dt.Columns.Add("Name");

dt.Columns.Add("TelePhone");

dt.Columns.Add("Email");

dt.Columns.Add("IngoreTest");//此字段为忽略字段,列添加此字段只是为了演示转换过程中确实会忽略该字段

DataRow dr1 = dt.NewRow();

dr1["ID"] = 1;

dr1["Name"] = "张三";

dr1["TelePhone"] = "123456";

dr1["Email"] = "test@test.com";

dr1["IngoreTest"] = "Ingore";

dt.Rows.Add(dr1);

DataRow dr2 = dt.NewRow();

dr2["ID"] = 2;

dr2["Name"] = "李四";

dr2["TelePhone"] = "456789";

dr2["Email"] = "qwer@test.com";

dr2["IngoreTest"] = "IngoreTest";

dt.Rows.Add(dr2);

ConvertToList ct = new ConvertToList();

List<CustomEntity> customs = ct.GetList<CustomEntity>(dt);

以上就是通过反射和特性实现转换的功能,更多用法请参考相关教程,谢谢!

C#反射与特性使用简介的更多相关文章

  1. .NET基础拾遗(4)委托、事件、反射与特性

    Index : (1)类型语法.内存管理和垃圾回收基础 (2)面向对象的实现和异常的处理基础 (3)字符串.集合与流 (4)委托.事件.反射与特性 (5)多线程开发基础 (6)ADO.NET与数据库开 ...

  2. 十七、C# 反射、特性和动态编程

    反射.特性和动态编程   1.访问元数据 2.成员调用 3.泛型上的反射 4.自定义特性 5.特性构造器 6.具名参数 7.预定义特性 8.动态编程   特性(attribute)是在一个程序集中插入 ...

  3. 利用反射的特性将DataReader对象转化为List集合

    问题:将SqlDataReader对象转换为List<T>集合 思路: 1,利用反射的特性得到对应实体Model的公共属性 Type type = typeof(T); PropertyI ...

  4. C#图解教程 第二十四章 反射和特性

    反射和特性 元数据和反射Type 类获取Type对象什么是特性应用特性预定义的保留的特性 Obsolete(废弃)特性Conditional特性调用者信息特性DebuggerStepThrough 特 ...

  5. .NET技术-1.0.使用反射、特性简化代码(验证Model类)

    使用反射.特性简化代码 参考项目:利用反射验证Model类/AssemblyVerification 假设现在有一个学生类(Student) /// <summary> /// 学生类 / ...

  6. C#根据反射和特性实现ORM映射实例分析

    本文实例讲述了C#根据反射和特性实现ORM 映射的方法.分享给大家供大家参考.具体如下: (一)关于反射 什么是反射? 反射就是在运行时,动态获取对象信息的方法.比如:运行时获得对象有哪些属性,方法, ...

  7. C#反射与特性(一):反射基础

    目录 C#反射与特性(一):反射基础 1. 说明 1.1 关于反射.特性 2. 程序集操作 2.1 获取 程序集对象(Assembly) 2.2 Assembly 使用 2.3 获取程序集的方式 C# ...

  8. C#反射与特性(五):类型成员操作

    目录 1,MemberInfo 1.1 练习-获取类型的成员以及输出信息 1.2 MemberType 枚举 1.3 MemberInfo 获取成员方法并且调用 1.4 获取继承中方法的信息(Decl ...

  9. C#反射与特性(六):设计一个仿ASP.NETCore依赖注入Web

    目录 1,编写依赖注入框架 1.1 路由索引 1.2 依赖实例化 1.3 实例化类型.依赖注入.调用方法 2,编写控制器和参数类型 2.1 编写类型 2.2 实现控制器 3,实现低配山寨 ASP.NE ...

随机推荐

  1. Golang实现requests库

    Golang实现requests库 简单的封装下,方便使用,像python的requests库一样. Github地址 Github 支持 GET.POST.PUT.DELETE applicatio ...

  2. redis消息队列,tp5.0,高并发,抢购

    redis处理抢购,并发,防止超卖,提速 1.商品队列(List列表),goods_list           控制并发,防止超卖 2.订单信息(Hash集合),order_info        ...

  3. Hadoop集群搭建过程中ssh免密码登录(二)

    一.为什么设置ssh免密码登录 在集群中,Hadoop控制脚本依赖SSH来执行针对整个集群的操作.例如,某个脚本能够终止并重启集群中的所有守护进程.所以,需要安装SSH,但是,SSH远程登陆的时候,需 ...

  4. 别以为真懂Openstack: 虚拟机创建的50个步骤和100个知识点(3)

    四.Nova-compute 步骤17:nova-compute接收到请求后,通过Resource Tracker将创建虚拟机所需要的资源声明占用 步骤18:调用Neutron API配置Networ ...

  5. 批处理修改IP

    1. 单次修改IP,批处理文件 newIP.bat @echo =========== Changing to IP : 222.192.41.%1 netsh interface ip set ad ...

  6. SQL Server索引碎片整理实际操作记录

    SQL Server 版本是 2008 R2. 查询数据库索引碎片情况的 SQL 语句(来源): SELECT OBJECT_NAME(ind.OBJECT_ID) AS TableName, ind ...

  7. 代码覆盖率 (Code Coverage)从简到繁 (一)

    代码覆盖率(Code Coverage)是反映测试用例对被测软件覆盖程度的重要指标,也是衡量测试工作进展情况的重要指标.它也是对测试工作进行量化的重要指标之一,测试工作往往不如开发那样激动人心,一个重 ...

  8. 机器学习基石笔记:Homework #1 PLA&PA相关习题

    原文地址:http://www.jianshu.com/p/5b4a64874650 问题描述 程序实现 # coding: utf-8 import numpy as np import matpl ...

  9. python网络-计算机网络基础(23)

    一.网络简介 网络是由节点和连线构成,表示诸多对象及其相互联系. 一个人玩: 两个人玩: 多个人玩: 说明 网络就是一种辅助双方或者多方能够连接在一起的工具 如果没有网络可想单机的世界是多么的孤单 使 ...

  10. 【Spark篇】---Spark中Action算子

    一.前述 Action类算子也是一类算子(函数)叫做行动算子,如foreach,collect,count等.Transformations类算子是延迟执行,Action类算子是触发执行.一个appl ...