C#反射与特性使用简介
本文是学习特性与反射的学习笔记,在介绍完特性和反射之后,会使用特性与反射实现一个简单的将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#反射与特性使用简介的更多相关文章
- .NET基础拾遗(4)委托、事件、反射与特性
Index : (1)类型语法.内存管理和垃圾回收基础 (2)面向对象的实现和异常的处理基础 (3)字符串.集合与流 (4)委托.事件.反射与特性 (5)多线程开发基础 (6)ADO.NET与数据库开 ...
- 十七、C# 反射、特性和动态编程
反射.特性和动态编程 1.访问元数据 2.成员调用 3.泛型上的反射 4.自定义特性 5.特性构造器 6.具名参数 7.预定义特性 8.动态编程 特性(attribute)是在一个程序集中插入 ...
- 利用反射的特性将DataReader对象转化为List集合
问题:将SqlDataReader对象转换为List<T>集合 思路: 1,利用反射的特性得到对应实体Model的公共属性 Type type = typeof(T); PropertyI ...
- C#图解教程 第二十四章 反射和特性
反射和特性 元数据和反射Type 类获取Type对象什么是特性应用特性预定义的保留的特性 Obsolete(废弃)特性Conditional特性调用者信息特性DebuggerStepThrough 特 ...
- .NET技术-1.0.使用反射、特性简化代码(验证Model类)
使用反射.特性简化代码 参考项目:利用反射验证Model类/AssemblyVerification 假设现在有一个学生类(Student) /// <summary> /// 学生类 / ...
- C#根据反射和特性实现ORM映射实例分析
本文实例讲述了C#根据反射和特性实现ORM 映射的方法.分享给大家供大家参考.具体如下: (一)关于反射 什么是反射? 反射就是在运行时,动态获取对象信息的方法.比如:运行时获得对象有哪些属性,方法, ...
- C#反射与特性(一):反射基础
目录 C#反射与特性(一):反射基础 1. 说明 1.1 关于反射.特性 2. 程序集操作 2.1 获取 程序集对象(Assembly) 2.2 Assembly 使用 2.3 获取程序集的方式 C# ...
- C#反射与特性(五):类型成员操作
目录 1,MemberInfo 1.1 练习-获取类型的成员以及输出信息 1.2 MemberType 枚举 1.3 MemberInfo 获取成员方法并且调用 1.4 获取继承中方法的信息(Decl ...
- C#反射与特性(六):设计一个仿ASP.NETCore依赖注入Web
目录 1,编写依赖注入框架 1.1 路由索引 1.2 依赖实例化 1.3 实例化类型.依赖注入.调用方法 2,编写控制器和参数类型 2.1 编写类型 2.2 实现控制器 3,实现低配山寨 ASP.NE ...
随机推荐
- 第一次冲刺意见汇总&团队第一阶段总结
大家对我们小组的意见基本是: 1.设计界面简单 2.功能较少 3.没有实现切换歌曲的功能 谢谢HT小组的走心评价 接下来我们组内准备:1.先调节用户界面,插入一些图片,美化界面,给用户直观的体验上升. ...
- 四种常用的access连接方式
整理出四种常用的access连接方式,当然,第1种这是最常用的(推荐使用).1. set dbconnection=Server.CreateOBJECT("ADODB.CONNECTION ...
- 企业IT管理员IE11升级指南【11】—— 通过SCCM 2012和WSUS部署Internet Explorer 11
企业IT管理员IE11升级指南 系列: [1]—— Internet Explorer 11增强保护模式 (EPM) 介绍 [2]—— Internet Explorer 11 对Adobe Flas ...
- kali linux学习笔记(四) : 网络端口大全介绍
端口大全介绍 2端口:管理实用程序 3端口:压缩进程 5端口:远程作业登录 7端口:回显 9端口:丢弃 11端口:在线用户 13端口:时间 17端口:每日引用 18端口:消息发送协议 19端口:字符发 ...
- #Java学习之路——第一部分总结
今天主要是Java的入门以及idea的安装说实话,没有什么有技术含量的东西,发的也全是皮毛,但是在数组部分有很多细节需要注意,在JDK环境变量配置的地方不光光只有windows 的环境配置,还要掌握补 ...
- [Swift]LeetCode106. 从中序与后序遍历序列构造二叉树 | Construct Binary Tree from Inorder and Postorder Traversal
Given inorder and postorder traversal of a tree, construct the binary tree. Note:You may assume that ...
- [Swift]LeetCode905. 按奇偶排序数组 | Sort Array By Parity
Given an array A of non-negative integers, return an array consisting of all the even elements of A, ...
- [Swift]LeetCode1014. 最佳观光组合 | Best Sightseeing Pair
Given an array A of positive integers, A[i] represents the value of the i-th sightseeing spot, and t ...
- Markdown语法及html内嵌
目录 1.Markdown介绍 2.Markdown语法介绍 3.内嵌html语法 之前看到很多大佬博客写的特别漂亮,非常羡慕,他们是怎么排版的呢?作为一个小白,学习使我快乐....终于在不断摸索 ...
- django启动server报错Error: That port is already in use.
这种一般是端口错误,一般是要把端口关掉,这里提供了两种方法. 方法一:直接命令: sudo lsof -t -i tcp:8000 | xargs kill -9 方法二:脚本:名字manage.py ...