反射不经常使用,可是在开发一些基础框架或公共类库,使用反射会使系统更加灵活,有时甚至是惟一的选择。反射是个庞大的话题,牵扯到的知识点也不少,包括程序集,自定义特性,泛型等等。
//获取Type实例三种方法:
1.1 Type t = Type.GetType("System.IO.Stream");
1.2 Type t = typeof(System.IO.Stream);
1.3 Type t = "Hello".GetType();
//Type类型的基本信息
Type t = "Hello".GetType();
t.Name; //获取类型名称
t.FullName;//获取类型全名
t.Namespace;//获取名称空间
t.BaseType;//获取对基类的Type类型的引用
t.UnderlyingSystemType;
t.Attributes;//获取TypeAttributes位标记
t.IsValueType;
t.IsByRef;
t.IsEnum;
t.IsClass;
t.IsInterface;
t.IsSealed;
t.IsPrimitive;//是否基类型
t.IsAbstract;
t.IsPublic;
t.IsVisible;
……
//Type类型的成员信息
//包含哪些字段,字段名称,类型,可访问性--FieldInfo
//包含哪些属性,属性名称,类型,可访问性--PropertyInfo
//包含哪些方法,方法名称,返回值,参数个数,参数类型,参数名称--MethodInfo
//事件 EventInfo 参数ParameterInfo
t.GetFields();
t.GetProperties();
t.GetMethods();
t.GetProperties();
t.GetConstructor();
t.GetMembers(BindingFlags.ExactBinding | BindingFlags.DeclaredOnly);
……
//位标记
//.NET中的枚举咱们通常有两种用法:
//一是表示惟一的元素序列,例如一周里的各天;
//还有就是用来表示多种复合的状态,这个时候通常须要为枚举加上[Flags]特性标记为位域
//例如:
[Flags]
public enum BindingFlags
{
Default = 0,
IgnoreCase = 1,
DeclaredOnly = 2,
Instance = 4,
Static = 8,
Public = 16,
NonPublic = 32,
FlattenHierarchy = 64,
InvokeMethod = 256,
CreateInstance = 512,
GetField = 1024,
SetField = 2048
}
1.1 Assembly am = Assembly.LoadFrom("Demo.dll");
1.2 Assembly am = Assembly.Load("Demo");
1.3 Assembly am = typeof(int).Assembly;
1.4 获取当前程序集
Assembly am = Assembly.GetExecutingAssembly();
am.FullName;//程序集名称
am.Location; //路径
am.GetTypes();//所有类型
am.GetType();//某个类型
am.GetModules();
am.GetModule();
am.GetCustomAttributes();
Module[] modules = am.GetModules();
foreach (Module module in modules)
{
Console.WriteLine("模块:" + module);
//Demo.dll
foreach (Type t in module.GetTypes())
Console.WriteLine("类型:" + module);
//Demo.BaseClass Demo.Delegate Demo.Struct Demo.Interface Demo.DemoClass
}
1.获取基本类型
2.获取成员信息和MemberInfo类型
3.字段信息和FieldInfo
4.属性信息和PropertyInfo
5.方法信息和MethodInfo
6.……
//反射枚举
public static class EnumManager<TEnum>
{
private static DataTable GetDataTable()
{
Type t = typeof (TEnum);
FieldInfo[] fieldInfos = t.GetFields();
DataTable table=new DataTable();
table.Columns.Add("Name", Type.GetType("System.String"));
table.Columns.Add("Value", Type.GetType("System.Int32"));
foreach (FieldInfo field in fieldInfos)
{
if (field.IsSpecialName)
{
DataRow row = table.NewRow();
row[0] = field.Name;
row[1] = Convert.ToInt32(field.GetRawConstantValue());
table.Rows.Add(row);
}
}
return table;
}
}
特性:特性是一种特殊的类型,能够加载到程序集的各类类型上,包括模块,类,接口,结构,构造函数,方法,方法参数等。特性是为程序集添加元数据的一种机制,经过他能够为编译器提供指示或对数据的说明。
1.自定义特性:
//AllowMultiple=true表示能够重复添加到一个类型上
[AttributeUsage(AttributeTargets.Class,AllowMultiple=true,Inherited = false)]
public class RecordAttribute:Attribute
{
private string recordType;
private string author;
private DateTime date;
private string memo;
public RecordAttribute(string recordType, string author, string date)
{
this.recordType = recordType;
this.author = author;
this.date = Convert.ToDateTime(date);
}
public string RecordType { get { return recordType; } }
public string Author { get { return author; } }
public DateTime Date { get { return date; } }
public string Memo { get { return memo; }set { memo = value; }}
}
2.使用特性
//特性使用:仅写成一行,无论是构造函数参数仍是属性,所有写到构造函数的圆括号中
//对应属性,采用“属性=值”的格式
[Record("更新","jackyfei","2016-08-24")]
[Record("建立","张飞洪","2016-08-14",Memo = "这个类是演示用的")]
public class DemoClass
{
}
3.反射特性
//使用特性对类型进行标记,目的是为了在程序中的某处使用它。
Type t = typeof(DemoClass);
object[] records = t.GetCustomAttributes(typeof (RecordAttribute), false);
foreach (RecordAttribute record in records)
{
Console.WriteLine("{0}", record);
Console.WriteLine(" 类型:{0}", record.RecordType);
Console.WriteLine(" 做者:{0}", record.Author);
Console.WriteLine(" 日期:{0}", record.Date.ToShortDateString());
Console.WriteLine(" 备注:{0}", record.Memo);
}
//获取到特性对象后,就能够任意处理了,好比说导出程序注释
前面的知识内容,主要是利用反射查看类型,查看特性,程序集,都是属于查看元数据的信息的内容。接下来将学习如何用反射动态建立一个对象。之因此叫动态,是由于能够字符串能够由各类途径得到
[Record("更新", "jackyfei", "2016-08-24")]
[Record("建立", "张飞洪", "2016-08-14", Memo = "这个类是演示用的")]
public class Calculator
{
private int x;
private int y;
public Calculator()
{
x = 0;
y = 0;
Console.WriteLine("x:{0},y:{1}", x, y);
}
public Calculator(int x,int y)
{
this.x = x;
this.y = y;
Console.WriteLine("x:{0},y:{1}",x,y);
}
public string GetStr()
{
return "hello,jackyfei";
}
public int Add()
{
int total = 0;
total = x + y;
return total;
}
public static int Add(int x,int y)
{
int total = x + y;
return total;
}
1. 使用无参构造函数创造对象
//建立对象一
Assembly am = Assembly.GetExecutingAssembly();
DemoClass demoClass= am.CreateInstance("NameSpace.DemoClass", true) as DemoClass;
Console.WriteLine(demoClass.GetStr());
//建立对象二
//第一个参数是程序集的名称,null表示当前程序集;
ObjectHandle handler = Activator.CreateInstance(null, "NameSpace.DemoClass");
handler.Unwrap();
2. 使用有参构造函数创造对象
Assembly am2 = Assembly.GetExecutingAssembly();
Object[] parameters=new object[2];
parameters[0] = 3;
parameters[1] = 5;
//BindingFlags用于限定类型成员的搜索,Default意思是不使用这个策略
am2.CreateInstance("NameSpace.DemoClass", true, BindingFlags.Default,
null, parameters, null, null);
1.1 InvokeMember()调用方式
Type t = typeof (Calculator);
Calculator c=new Calculator(3,5);
int rst =(int)t.InvokeMember("Add", BindingFlags.InvokeMethod, null, c, null);
Console.WriteLine("x+y={0}", rst);
object[] p = {6, 7};
int rst2 = (int)t.InvokeMember("Add", BindingFlags.InvokeMethod, null, t, p);
Console.WriteLine("x+y={0}", rst2);
//调用静态方法,他不是基于某个具体的类型实例,而是基于类型自己,
//因此传递的参数是typeof(Calculator)
1.2 GetMethod()调用方式
Type t = typeof (Calculator);
Calculator c=new Calculator(3,5);
//BindingFlags.Instance 调用实例方法
MethodInfo mi = t.GetMethod("Add", BindingFlags.Instance | BindingFlags.Public);
int rst = (int)mi.Invoke(c, null);
Console.WriteLine("x+y={0}", rst);
//BindingFlags.Static 调用静态方法
object[] p = { 6, 9 };
MethodInfo mi2 = t.GetMethod("Add", BindingFlags.Static | BindingFlags.Public);
int rst2 = (int)mi2.Invoke(null, p);
Console.WriteLine("x+y={0}", rst2);