您的位置:首页 > 编程语言 > C#

C#反射与自定义属性

2010-03-27 11:30 375 查看
具体什么是反射就不再多解释了,通俗一点就是可以由类型得到其相关的信息(事实上如果是方法的话我们还可以去调用)。好了先看一看几个例子:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Globalization;
namespace Reflection
{
    class MyFather
    {
        public MyFather()
        {
        }
        public int FatherMethodOne()
        {
            return 1;
        }
        protected void FatherMethodTwo()
        {
            Console.WriteLine("FatherMethodTwo!");
        }
        private void FathodMethodThree()
        {
            Console.WriteLine("FathodMethodThree!");
        }
    }
    class MyTest : MyFather
    {
        private int i;
        private int j = 10;
        public int k;
        public MyTest()
        {
        }
        public MyTest(int i)
        {
            this.i = i;
        }
        public int MethodOne()
        {
            return i * j;
        }
        public static int MethodTwo()
        {
            return 10;
        }
        private void MethodThree()
        {
            Console.WriteLine("MethodThree!");
        }
    }
    class Program
    {
        //static void Main(string[] args)
        //{
        //    /*反射的核心是Type类,它封装了对象的信息,是反射的入口
        //     * 获得Type实例有两种方式:已加载程序集的和未加载程序集的
        //     * 前者有三种方法:
        //     * 
        //     */
        //    Type tp = Type.GetType("System.IO.Stream");//方法一:用Type类的静态方法
        //    Console.WriteLine(tp.ToString());
        //    Type tp2 = typeof(System.IO.Stream);//方法二:使用typeof
        //    Console.WriteLine(tp2.ToString());
        //    string str = "cmjstudio";
        //    Console.WriteLine(str.GetType());//方法三:通过类型实例来获得
        //}
        //获取信息
        static void Main(string[] args)
        {
            //基本信息
            Type tp = Type.GetType("Reflection.MyTest");
            Console.WriteLine(tp.ToString());
            Console.WriteLine(tp.Name);
            Console.WriteLine(tp.FullName);
            Console.WriteLine(tp.Namespace);
            Console.WriteLine(tp.BaseType);
            Console.WriteLine(tp.UnderlyingSystemType);
            Console.WriteLine(tp.Attributes);
            Console.WriteLine(tp.IsAbstract);
            Console.WriteLine(tp.IsAnsiClass);
            Console.WriteLine(tp.IsArray);
            Console.WriteLine(tp.IsAutoClass);
            Console.WriteLine(tp.IsAutoLayout);
            Console.WriteLine(tp.IsByRef);
            Console.WriteLine(tp.IsClass);
            Console.WriteLine(tp.IsEnum);
            Console.WriteLine("......");
            Console.WriteLine("---------------------------------------------");
            //成员信息
            MemberInfo[] mi = tp.GetMembers();
            foreach (MemberInfo mit in mi)
            {
                Console.WriteLine("成员:" + mit.ToString() + " 类型" + mit.MemberType);
            }
            Console.WriteLine("*****");
            //对成员信息过滤
            MemberInfo[] mi2 = tp.GetMembers(BindingFlags.Static | BindingFlags.Public);
            foreach (MemberInfo mit in mi2)
            {
                Console.WriteLine("成员:" + mit.ToString() + " 类型" + mit.MemberType);
            }
            Console.WriteLine("*****");
            //查找成员信息
            MemberInfo[] mi3 = tp.FindMembers(MemberTypes.Method, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly, Type.FilterName, "*");
            foreach (MemberInfo mit in mi3)
            {
                Console.WriteLine("成员:" + mit.ToString() + " 类型" + mit.MemberType);
            }
            Console.WriteLine("---------------------------------------------");
            //事实上对于方法我们可以通过下面的方法(GetMethods不返回构造函数)
            MethodInfo[] mi4 = tp.GetMethods();
            foreach (MethodInfo m in mi4)
            {
                Console.WriteLine("方法名:" + m.Name + "类型:" + m.MemberType);
            }
            Console.WriteLine("****");
            //如果要指定BindingFlags,为了获取返回值,必须指定 BindingFlags.Instance  或 BindingFlags.Static。
            MethodInfo[] mi5 = tp.GetMethods(BindingFlags.Public | BindingFlags.Static);
            foreach (MethodInfo m in mi5)
            {
                Console.WriteLine("方法名:" + m.Name + "类型:" + m.MemberType);
            }
            Console.WriteLine("****");
            //得到方法信息可以调用(不管该方法是不是私有的,所以也违背了面向对象的封装特性)
            MethodInfo[] mi6 = tp.GetMethods(BindingFlags.Instance | BindingFlags.NonPublic);
            foreach (MethodInfo m in mi6)
            {
                if (m.IsPrivate)
                {
                    Console.WriteLine("方法名:" + m.Name + "类型:" + m.MemberType);
                    MyTest mt2 = new MyTest();
                    m.Invoke(mt2, null);
                }
            }
            //和GetMethods类似的还有tp.GetProperties()、tp.GetConstructors()等不再举例
            Console.ReadKey();
        }
    }
}




上面列举了基本上所有常用的反射方面的内容,当然上面的例子都是在已经存在相应的类的基础上,如果这个类我是在一个dll类库中怎么办呢?请看下面的例子:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Reflection
{
    class Program2
    {
        public static void Main(string[] args)
        {
            System.Reflection.Assembly assembly = System.Reflection.Assembly.LoadFile(@"F:/CSharp/ADO.NETExtend/Reflection/MyLibrary/bin/Debug/MyLibrary.dll");
            Type tp = assembly.GetType("MyLibrary.MyClass");
            Console.WriteLine(tp.Name);
            System.Reflection.MethodInfo[] mi = tp.GetMethods(System.Reflection.BindingFlags.Instance);
            foreach (System.Reflection.MethodInfo m in mi)
            {
                m.Invoke(new MyLibrary.MyClass(),new object[]{1,"cs"});
            }
            MyLibrary.MyClass mc2 = System.Reflection.Assembly.Load("MyLibrary").CreateInstance("MyLibrary.MyClass") as MyLibrary.MyClass;
            mc2.ID = 1;
            mc2.Name = "cmj";
            mc2.PrintInfo();            
            
        }
    }
}




这里提供了两种方法。

好了,如果看看上面的例子我想对反射也有了初步的了解,但是怎么去用呢。对了,在工厂模式中我们用到了,还有什么呢?那就是反射和自定义属性的结合,这个太重要了。如果我们有这样的需求,需要自己来做个orm映射,实体类很简单,但是如果知道相应的表的信息呢?相信很多用过orm框架的朋友都知道我们很多时候需要在实体类和相关属性上做标记属性,对了其实我们是通过比较熟悉来得到相应的信息的,更准确的说是我们通过反射得到实体类的信息,进而通过GetCustomAttributes方法得到相应的标记属性的信息,而这信息信息我们之前已经写在了比较属性中。我们来看看具体的例子(自定义属性不再多说,这里主要是反射和自定义属性的结合。):

两个自定义属性:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
namespace ReflectionAndAttribute 
{ 
    [AttributeUsage(AttributeTargets.Class|AttributeTargets.Interface)] 
    class TableNameAttribute:Attribute 
    { 
        public TableNameAttribute() 
        { 
        } 
        public string TName 
        { 
            get; 
            set; 
        } 
    } 
}




using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
namespace ReflectionAndAttribute 
{ 
    //类名以Attribute结尾,继承于Attribute 
    [AttributeUsage(AttributeTargets.Property , AllowMultiple = false, Inherited = false)]//指明作用对象 
    class ColumnNameAttribute:Attribute 
    { 
        //至少保护一个构造函数 
        public ColumnNameAttribute() 
        { 
        } 
        public string CName 
        { 
            get; 
            set; 
        } 
    } 
}




相应的获得方法和测试方法

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Reflection; 
namespace ReflectionAndAttribute 
{ 
    class Program 
    { 
        static void DisplaySelfAttribute<T>()where T:class ,new () 
        { 
            string tableName = string.Empty; 
            List columnNames = new List(); 
            Type tp = typeof(T);
            //得到属性上的标记属性信息即列名 
            foreach(PropertyInfo pi in tp.GetProperties()) 
            { 
                object[] objAttributes = pi.GetCustomAttributes(typeof(ColumnNameAttribute), true); 
                if (objAttributes.Length > 0) 
                { 
                    ColumnNameAttribute cnAttribute = objAttributes[0] as ColumnNameAttribute; 
                    if (cnAttribute != null) 
                    { 
                        columnNames.Add(cnAttribute.CName); 
                    } 
                } 
            } 
            //得到类上标记信息即表名 
            object[] objAttribute2 = tp.GetCustomAttributes(typeof(TableNameAttribute), true); 
            if (objAttribute2.Length > 0) 
            { 
                TableNameAttribute tnAttribute = objAttribute2[0] as TableNameAttribute; 
                if (tnAttribute != null) 
                { 
                    tableName = tnAttribute.TName; 
                } 
            } 
            //显示相关信息 
            Console.WriteLine("表名是:"+tableName); 
            Console.WriteLine("列名分别是:"); 
            foreach (string str in columnNames) 
            { 
                Console.WriteLine(str); 
            } 
        } 
        static void Main(string[] args) 
        { 
            DisplaySelfAttribute<TestClass>(); 
        } 
    } 
}




多余的话我就不说了注释很明白,或许有朋友说这样的代码没有用啊,其实如果我们对DisplaySelfAttribute进行修改例如我们修改成delete方法,这样我么有了表名,我们就可以构造sql语句执行删除了(当然在那之前需要多一个属性就是判断是否是主键)。这样的话自己做个orm框架也是不成问题的!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: