村长

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

本文整理所得:

一、杂谈(比较详细)

C#反射Reflection学习随笔(完结篇)_AX

文章出处:http://www.cnblogs.com/axzhz/archive/2006/11/01/546493.html

【开篇】
这篇帖子真的憋了好久.无处下笔啊!
搜了搜园子,已经有棵这方面的好白菜了!链接如下
http://www.cnblogs.com/whxleem/category/4641.html

以此为资料,学习了一下,但心有不甘,要不前两篇许下的承诺就没法实现了!于是有了这篇帖子.

【正文】
①什么是反射?
反射提供了封装程序集、模块和类型的对象。
您可以使用反射动态地创建类型的实例(见④ ),将类型绑定到现有对象(这个不会),或从现有对象中获取类型(见②③ )。然后,可以调用类型的方法或访问其字段和属性。
最最简单的反射:如下

 1using System;
 2using System.Reflection;
 3namespace TestReflection
 4 {
 5    class Program
 6    {
 7        static void Main(string[] args)
 8        {
 9            //创建两个对象【object和Objetct好像没有区别啊??连提示都一样!】
10            object A = new AX();
11            Object B = new AXzhz();
12            //获取对象的类型
13            new TestObjectType().TestObjectTypeNow(A, B);            
14        }

15    }

16
17    class AX
18    {
19    }

20
21    class AXzhz
22    {
23    }

24
25    class TestObjectType
26    {
27        //构造函数的默认修饰为private
28        internal void TestObjectTypeNow(object A, object B)
29        {
30            Type tpA = A.GetType();
31            Type tpB = B.GetType();
32            Console.WriteLine(tpA.FullName);
33            Console.WriteLine(tpB.FullName);
34            Console.ReadLine();
35        }

36    }

37}


输出结果:
TestReflection.AX
TestReflection.AXzhz
【分析】通过对象实例(A,B),可以使用GetType()方法获取该对象属于哪个类.非类型转化后的类,而是构造该类型的类
【应用】给个变量/对象实例,测试下它属于哪个类,顺带还给出该类所属的Assembly
【附】另外一种获取类型的方法是通过Type.GetType以及Assembly.GetType方法,如:
       Type t = Type.GetType("TestReflection.AX");
    需要注意的是,前面我们讲到了命名空间和装配件的关系,要查找一个类,必须指定它所在的装配件
Type类:表示类型声明:类类型、接口类型、数组类型、值类型、枚举类型、类型参数、泛型类型定义,以及开放或封闭构造的泛型类型。     发晕,对泛型没研究.

②我们获得的Type实例有什么用?
   ⅰ获得类名:如上面例子的FullName属性,返回TestReflection.AX
       这个也比较恶心,直接用A.ToString();返回的也是这个结果.
   ⅱ创建该类的对象.你首先通过ⅰ来获得类名AX
       AX ax = (AX)Activator.CreateInstance(tpA);
       都知道是AX类型了,怎么不new一个???鸡肋的东西.
      上面的【附】真不知道是干嘛吃的,都知道了类TestReflection.AX,直接new一个就可以了.
    ⅲ获得对象所属类的相关信息
         通过tpA的相关属性,来得到该类的相关信息.
         其实你通过A的相关属性,也可以得到该类的相关信息.还简单省事,真不知道Type类到底是干嘛吃的.

窥一斑而知全豹,一个对象实例泄漏的密秘(这个比较爽)
通过一个对象实例,我们可以获得包含这个对象实例的类的Assembly,进而获得整个Assembly的信息.

 1using System;
 2using System.Reflection;
 3namespace TestReflection
 4{
 5    class Program
 6    {
 7        public static void Main(string[] args)
 8        {
 9            object A = new AX();
10            //获取对象所属的Assembly的所有类的基本信息
11            new TestObjectType().TestObjectTypeNow(A);
12        }

13    }

14
15    class AX
16    {
17        internal int kkkkkkkk = 0;
18        public int ooooooooo;
19        private int property;
20
21        public int Property
22        {
23            get return property; }
24            set { property = value; }
25        }

26        public void A()
27        {
28            Console.WriteLine("AX's function!~");
29        }

30    }

31
32    class AXzhz
33    {
34    }

35
36    class TestObjectType
37    {
38        //构造函数的默认修饰为private
39        internal void TestObjectTypeNow(object A)
40        {
41            Type tpA = A.GetType();
42            Assembly assembly = tpA.Assembly;
43            Type[] types = assembly.GetTypes();
44            foreach (Type type in types)
45            {
46                Console.WriteLine("【类名】"+type.FullName);
47                //获取类型的结构信息
48                ConstructorInfo[] myconstructors = type.GetConstructors();
49                Show(myconstructors);
50                //获取类型的字段信息
51                FieldInfo[] myfields = type.GetFields();
52                Show(myfields);
53                //获取方法信息
54                MethodInfo[] myMethodInfo = type.GetMethods();
55                Show(myMethodInfo);
56                //获取属性信息
57                PropertyInfo[] myproperties = type.GetProperties();
58                Show(myproperties);
59                //获取事件信息,这个项目没有事件,所以注释掉了,
60                //通过这种办法,还可以获得更多的type相关信息.
61                //EventInfo[] Myevents = type.GetEvents();
62                 //Show(Myevents);
63            }

64            Console.ReadLine();
65        }

66        //显示数组的基本信息
67        public void Show(object[] os)
68        {
69            foreach (object var in os)
70            {
71                Console.WriteLine(var.ToString());
72            }

73            Console.WriteLine("----------------------------------");
74        }

75    }

76}


【注】通过测试,发现只能获得public类型的信息.

④动态创建对象实例【经典】
是实现抽象工厂的基础,也是实现抽象工厂的核心技术,通过它,可以动态创建一个你想要的对象.如下面的例子是演示如何动态创建ChineseName或EnglishName的实例

 
 1using System;
 2using System.Reflection;
 3namespace TestReflection
 4{
 5    class AXzhz_sReflectionExample
 6    {
 7        public static void Main()
 8        {
 9            IName name=AbstractFactory.GetName();
10            name.ShowName();
11        }

12    }

13
14    public class AbstractFactory
15    {
16        public static IName GetName()
17        {
18            //s的值以后从Web.config动态获取
19            //把s赋值为:TestReflection.EnglishName,将显示英文名
20            string s = "TestReflection.ChineseName";
21            IName name = (IName)Assembly.Load("TestReflection").CreateInstance(s);
22            return name;
23        }

24    }

25    
26    //声明一个接口,它有一个显示"名字"的功能
27    public interface IName
28    {
29        void ShowName();
30    }

31
32    //实现接口,显示中国名字
33    public class ChineseName : IName
34    {
35        public void ShowName()
36        {
37            Console.WriteLine("我叫AX!");
38            Console.ReadLine();
39        }

40    }

41
42    //实现接口,显示英国名字
43    public class EnglishName:IName
44    {
45        void IName.ShowName()
46        {
47            Console.WriteLine("My name is AXzhz!");
48            Console.ReadLine();
49        }

50    }

51}

⑤获得整个解决方案的所有Assembly(这个有点用)
如果你不太清楚自己的解决方案中都用到了哪些Assembly,可以使用下面的方法,如果再想得到Assembly里的信息,见③

 1using System;
 2using System.Reflection;
 3
 4namespace TestReflection
 5{
 6    class ShowAllAssembly
 7    {
 8        public static void Main()
 9        {
10            //获得解决方案的所有Assembly
11            Assembly[] AX = AppDomain.CurrentDomain.GetAssemblies();
12            //遍历显示每个Assembly的名字
13            foreach (object var in AX)
14            {
15                Console.WriteLine("Assembly的名字:"+var.ToString());                
16            }

17            //使用一个已知的Assembly名称,来创建一个Assembly
18            //通过CodeBase属性显示最初指定的程序集的位置
19            Console.WriteLine("最初指定的程序集TestReflection的位置:" + Assembly.Load("TestReflection").CodeBase);
20            Console.ReadLine();
21        }

22    }

23}

24
 二、动态生成类通过反射调用

C#强化系列文章五:动态代码的使用(反射和动态生成类)

在软件开发尤其是框架和底层开发时,为了更灵活的控制代码,常常需要进行一些动态的操作。比如根据用户的输入等动态的调用类中的方法或者根据数据库表结构、用户要求动态的生成一些类,然后再动态的调用类中的方法。当然使用这些方式时会对性能有一点影响,具体使用过程中可以根据实际情况来定,不过一般的B/S开发中主要的瓶颈还是在数据库操作和网速方面,这点影响应该可以忽略的
下面我就从这两个方面来说说动态代码的使用:
一、反射的使用
可以使用反射动态地创建类型的实例,将类型绑定到现有对象,或从现有对象中获取类型。然后,可以调用类型的方法或访问其字段和属性。
需要使用的命名空间:System.Reflection
反射的作用很多,下面的例子主要是看一下怎么动态的调用类中的方法。

    class ReflTest1
    
{
        
private string _prop1;

        
public string Prop1
        
{
            
get return _prop1; }
            
set { _prop1 = value; }
        }

    
        
public void Write1(string strText)
        
{
            Console.WriteLine(
"111111111:" + strText);
        }

        
public void Write2(string strText)
        
{
            Console.WriteLine(
"222222222:" + strText);
        }

        
public void MyWrite(string strText)
        
{
            Console.WriteLine(
"3333333333:" + strText);
        }

    }

这个例子中提供了三个方法和一个属性,下面的代码来动态的调用它们:
            string strText = "abcd";

            BindingFlags flags 
= (BindingFlags.NonPublic | BindingFlags.Public |
                BindingFlags.Static 
| BindingFlags.Instance | BindingFlags.DeclaredOnly);

            Type t 
= typeof(ReflTest1);
            MethodInfo[] mi 
= t.GetMethods(flags);
            Object obj 
= Activator.CreateInstance(t);

            
foreach (MethodInfo m in mi)
            
{
                
if (m.Name.StartsWith("Write"))
                
{
                    m.Invoke(obj, 
new object[] { strText });
                }

            }


            MethodInfo mMy 
= t.GetMethod("MyWrite");
            
if (mMy != null)
            
{
                mMy.Invoke(obj, 
new object[] { strText });
            }

BindingFlags用来设置要取得哪些类型的方法,然后我们就可以取得这些方法来动态的调用。(当然为了可以循环的调用方法,在方法的命名方面可以自己指定一个规则)

二、动态生成类
我们可以在程序运行过程中调用.NET中提供的编译类,动态的将一段string编译成一个类,然后再通过反射来调用它
需要使用的命名空间:System.CodeDom System.CodeDom.Compiler Microsoft.CSharp System.Reflection
动态创建、编译类的代码如下:
        public static Assembly NewAssembly()
        
{
            
//创建编译器实例。   
            provider = new CSharpCodeProvider();
            
//设置编译参数。   
            paras = new CompilerParameters();
            paras.GenerateExecutable 
= false;
            paras.GenerateInMemory 
= true;

            
//创建动态代码。   
            StringBuilder classSource = new StringBuilder();
            classSource.Append(
"public   class   DynamicClass \n");
            classSource.Append(
"{\n");

            
//创建属性。   
            classSource.Append(propertyString("aaa"));
            classSource.Append(propertyString(
"bbb"));
            classSource.Append(propertyString(
"ccc"));

            classSource.Append(
"}");

            System.Diagnostics.Debug.WriteLine(classSource.ToString());

            
//编译代码。   
            CompilerResults result = provider.CompileAssemblyFromSource(paras, classSource.ToString());

            
//获取编译后的程序集。   
            Assembly assembly = result.CompiledAssembly;

            
return assembly;
        }


        
private static string propertyString(string propertyName)
        
{
            StringBuilder sbProperty 
= new StringBuilder();
            sbProperty.Append(
" private   int   _" + propertyName + "   =   0;\n");
            sbProperty.Append(
" public   int   " + "" + propertyName + "\n");
            sbProperty.Append(
" {\n");
            sbProperty.Append(
" get{   return   _" + propertyName + ";}   \n");
            sbProperty.Append(
" set{   _" + propertyName + "   =   value;   }\n");
            sbProperty.Append(
" }");
            
return sbProperty.ToString();
        }
propertyString方法就是用来拼写字符串的
整个代码比较简单,主要步骤就是:1、拼写类的字符串  2、调用CSharpCodeProvider类进行编译得到程序集(assembly)

接下来就可以利用之前反射的方法来动态调用这个类中的属性了:
            Assembly assembly = NewAssembly();

            
object Class1 = assembly.CreateInstance("DynamicClass");
            ReflectionSetProperty(Class1, 
"aaa"10);
            ReflectionGetProperty(Class1, 
"aaa");

            
object Class2 = assembly.CreateInstance("DynamicClass");
            ReflectionSetProperty(Class1, 
"bbb"20);
            ReflectionGetProperty(Class1, 
"bbb");
DynamicClass是我动态类的类名,aaa和bbb是其中的属性
ReflectionSetProperty和ReflectionGetProperty代码如下:

        private static void ReflectionSetProperty(object objClass, string propertyName, int value)
        
{
            PropertyInfo[] infos 
= objClass.GetType().GetProperties();
            
foreach (PropertyInfo info in infos)
            
{
                
if (info.Name == propertyName && info.CanWrite)
                
{
                    info.SetValue(objClass, value, 
null);
                }

            }

        }


        private static void ReflectionGetProperty(object objClass, string propertyName)
        
{
            PropertyInfo[] infos 
= objClass.GetType().GetProperties();
            
foreach (PropertyInfo info in infos)
            
{
                
if (info.Name == propertyName && info.CanRead)
                
{
                    System.Console.WriteLine(info.GetValue(objClass, 
null));
                }

            }

        }


三、根据类型获取对象并调用方法

1 创建用于反射使用的DLL

新建一个C#类库项目,拷贝源代码如下,编译生成DLL(假如DLL的文件名是TestReflect.dll)

 1using System;
 2
 3namespace Webtest
 4{
 5 /// <summary>
 6 /// ReflectTest 的摘要说明。
 7 /// </summary>

 8 public class ReflectTest
 9 {
10  public ReflectTest()
11  {}
12
13  public string WriteString(string s)
14  {
15   return "欢迎您," + s;
16  }

17
18  /// <summary>
19  /// dsajkjflasjdfalksdjfaskfd
20  /// </summary>
21  /// <param name="s"></param>
22  /// <returns></returns>

23  public static string WriteName(string s)
24  {
25   return "欢迎您光临," + s;
26  }

27
28  public string WriteNoPara()
29  {
30   return "您使用的是无参数方法";
31  }

32 }

33}

34
35
36

2 应用于反射的例子

在ASPNET页面中加入以下函数:

 1public void test1()
 2  {
 3   System.Reflection.Assembly ass;
 4   Type type ;
 5   object obj;
 6   try
 7   {
 8    ass = System.Reflection.Assembly.LoadFile(@"d:\TestReflect.dll");
 9    type = ass.GetType("Webtest.ReflectTest");//必须使用名称空间+类名称
10    System.Reflection.MethodInfo method = type.GetMethod("WriteString");//方法的名称
11    obj = ass.CreateInstance("Webtest.ReflectTest");//必须使用名称空间+类名称
12    string s = (string)method.Invoke(obj,new string[]{"jianglijun"}); //实例方法的调用
13   
14    Response.Write(s+"<br>");
15    method = type.GetMethod("WriteName");//方法的名称
16    s = (string)method.Invoke(null,new string[]{"jianglijun"}); //静态方法的调用
17    Response.Write(s+"<br>");
18
19    method = type.GetMethod("WriteNoPara");//无参数的实例方法
20    s = (string)method.Invoke(obj,null);
21    Response.Write(s+"<br>");
22    method = null;
23   }

24   catch(Exception ex)
25   {
26    Response.Write(ex+"<br>");
27   }

28   finally
29   {
30    ass = null;
31    type = null;
32    obj = null;
33   }

34  }

35

http://www.cnblogs.com/fineboy/archive/2005/09/02/228684.html

http://www.cnblogs.com/jax/archive/2009/10/16/1584527.html

posted on 2011-04-10 17:28  Say No  阅读(198)  评论(0编辑  收藏  举报