代码改变世界

NET反射系统

2012-02-18 19:51  海不是蓝  阅读(547)  评论(0编辑  收藏  举报

   没事看书的笔记,虽然这些知识在项目中经常用,但是系统的看看书也对得起这买书的钱。。。

 

Type

 

    查看msdn知道反射的所有东西都是在Reflection中,想获取什么就去自己查查相关的类就好了,用了反射这么久,觉得其实核心就是那个Type。

 

   Type派生于MemberInfo这个抽象类。其实想想,当你获取到了一个Type对象的时候,那么就应该能点出什么得到这个对象的名称,属性,方法这些,所以整个反射系统都是这样的,所以没必要去每个类和方法都看,用的时候右键转到定义看看就好。

 

 

        static void Main(string[] args)
{
//不管什么,先得到Type
Type t = typeof(A);

Console.WriteLine("类型名称:{0}", t.Name);

//得到类型中的字段集合,但是私有的字段不会被我们获取到
//所以大牛们或者老师们都苦口良心的说重要私有的东西都private
Console.WriteLine();
FieldInfo[] fields = t.GetFields();
foreach (FieldInfo f in fields)
{
//FieldInfo还有很多东西,需要用的时候右键转到定义看看就行
Console.WriteLine("{1} Field:{0}", f.Name, f.IsPublic ? "Public" : "Private");
}

//获取下Type中的方法,有道词典查查方法这个单词,原来是method,那么应该有个MethodInfo这个类吧
MethodInfo[] methods = t.GetMethods(BindingFlags.Public | BindingFlags.Static);
foreach (MethodInfo m in methods)
{
Console.Write("{0} {1}", m.IsPublic ? "Public" : "Private", m.Name);
//获取下方法的参数
StringBuilder pstr = new StringBuilder();
ParameterInfo[] par = m.GetParameters();
foreach (ParameterInfo p in par)
{
pstr.AppendFormat(",{0} {1}", p.ParameterType.Name, p.Name);
}
Console.Write("({0})", pstr.ToString() != string.Empty ? pstr.ToString().Substring(1) : string.Empty);
//获取返回值
Console.Write(" return {0}", m.ReturnType.Name);
Console.WriteLine();
}

Console.WriteLine();
Console.Read();
}
public class A
{
public string name;
public string name1;
private Int32 sum;

public void Show()
{
Console.WriteLine(this.name);
}

public static Int32 Test(Int32 i)
{
return i;
}
}

 

注意这里把基类object的方法成员也显示了。

可以根据枚举值来限定获取的方法

public abstract MethodInfo[] GetMethods(BindingFlags bindingAttr);

获取公开静态的方法

MethodInfo[] methods = t.GetMethods(BindingFlags.Public | BindingFlags.Static);

   注意这里:假如只写个公开的枚举值,那么就无法获取到方法,应该至少包含 是否静态或实例枚举值和是否公开枚举值。

 

反射调用方法

 

public abstract class MethodBase

public object Invoke(object obj, object[] parameters);

   假如要调用的方法是实例方法,那么第一个参数就是对象,静态方法就是null,后面的是参数集合。


static void Main(string[] args)
{
//不管什么,先得到Type
A a = new A();
Type t = a.GetType();

Console.WriteLine("类型名称:{0}", t.Name);

//获取下Type中的方法,有道词典查查方法这个单词,原来是method,那么应该有个MethodInfo这个类吧
MethodInfo[] methods = t.GetMethods(BindingFlags.DeclaredOnly
| BindingFlags.Public | BindingFlags.Instance);//过滤掉父类的方法
foreach (MethodInfo m in methods)
{
//调用方法
if (m.Name == "Show")
m.Invoke(a, new object[] { "hello" });
Console.WriteLine();
}

Console.WriteLine();
Console.Read();
}
public class A
{

public void Show(string name)
{
Console.WriteLine(name);
}
}


调用构造函数创建类型对象

   前面的例子都是自己手动创建个类型对象,这样还不如直接去调用那些方法。

当在有些特殊的需求中需要在运行时来创建对象,这样反射的优势就体现出来了。

反射创建对象其中的一个方法就是去调用类型的构造函数。

注意这个方法返回的是object

public object Invoke(object[] parameters);

 

 

  static void Main(string[] args)
{
//不管什么,先得到Type
A a = new A();
Type t = a.GetType();

Console.WriteLine("类型名称:{0}", t.Name);

//获取类型的构造函数,这里我们只需要创建一个默认构造函数的对象,所以构造函数的参数为0
object obj = null;
ConstructorInfo[] Con = t.GetConstructors();
foreach (ConstructorInfo c in Con)
{
if (c.GetParameters().Length == 0)
{
obj = c.Invoke(null);
}
}

//现在我们将obj转换成类型A
if (obj != null)
{
A a1 = obj as A;
a1.Show("abc");
}
else
Console.WriteLine("糟糕!");

Console.WriteLine();
Console.Read();
}
public class A
{

public void Show(string name)
{
Console.WriteLine(name);
}
}


通过程序集来获取类型对象

   前面的情况都是建立在我们知道A这个类,反射的功能是超级强大的,当你不知道一个程序集中有那些类型对象,那么用反射去寻找程序集中的类型。


程序集这个类中有很多加载程序集的方法,请选择最适合当前情况的。

public static Assembly Load(string assemblyString);

public static Assembly LoadFile(string path);

public static Assembly LoadFrom(string assemblyFile);

上面这3个还有很多重载的方法,所以要具体去了解那么就去msdn看吧。


 

static void Main(string[] args)
{
//通过程序集获取类型对象
Assembly asm = Assembly.Load("ConsoleApplication2");
Type[] type = asm.GetTypes();
foreach (Type t in type)
{
Console.WriteLine("类型名称:{0}", t.Name);
}
Console.WriteLine();
Console.Read();
}
public class A
{

public void Show(string name)
{
Console.WriteLine(name);
}
}
public class B { }

 


 

到这里,其实你已经想到了可以自己完成一个程序,比如全自动类型查询。

 

 

作者:海不是蓝

博客:http://www.cnblogs.com/hailan2012/

邮箱:hailan2012@sina.com

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。