反射和注解

C#语言提供了反射(Reflection)的特性,通过反射我们能够获取程序集内部的类、属性、注解等,还可以根据类名动态实例化对象、根据方法名调用方法。而注解(Attribute)配合反射使用能实现很多强大的功能,比如依赖注入、数据验证等。

反射

Type 类对象

C#中,Type是一个表示类型的类对象,类似Java中的Class。其中包含了类型、全限定名、父类类型、成员属性等重要信息。获取类对象有三种方式:

  1. 通过typeof运算符获取类型
  2. 调用object.GetType()获取类型
  3. 调用Type.GetType(string typeName)根据类名获取类型

以下例子代码中,使用这三种方式获取类型对象:

using System;

namespace Gacfox.Demo.DemoNetCore
{
    class Student { }

    class Program
    {
        static void Main()
        {
            // 通过typeof获取类型
            Type t1 = typeof(Student);
            // 通过对象获取类型
            Student s = new Student();
            Type t2 = s.GetType();
            // 通过字符串获取类型
            Type t3 = Type.GetType("Demo.Student");
        }
    }
}

获取类成员

Type对象中包含了一系列方法,能够获取类的字段、属性、方法等。

using System;
using System.Reflection;

namespace Gacfox.Demo.DemoNetCore
{
    class Student
    {
        public int Id;
        public string StuName { get; set; }
    }

    class Program
    {
        static void Main()
        {
            Type type = typeof(Student);
            // 获取public字段
            FieldInfo[] fieldInfos = type.GetFields();
            // 获取属性
            PropertyInfo[] propertyInfos = type.GetProperties();
            // 获取方法
            MethodInfo[] methodInfos = type.GetMethods();
        }
    }
}

Activator

Activator能够根据Type类型实例化对象。

Student s = Activator.CreateInstance(typeof(Student)) as Student;

注解

注:实际上C#的Attribute直译是“特性”,这个翻译就比较奇葩了,我这里就沿用Java的叫法“注解”。不过实际上Java的注解是仿照C#的语法特性,是后出现的。

注解的使用

Attribute一般都需要配合反射来使用,这里我们直接看一个例子,下面代码中我们实现了一个基于Attribute的数据验证功能。

using System;
using System.Reflection;

namespace Gacfox.Demo.DemoNetCore
{
    [AttributeUsage(AttributeTargets.Property)]
    public class MaxLength : Attribute
    {
        public int Length { get; set; }

        public MaxLength(int length)
        {
            this.Length = length;
        }
    }

    class ValidateUtil
    {
        public static bool Valid(object o)
        {
            Type t = o.GetType();
            foreach (PropertyInfo info in t.GetProperties())
            {
                foreach (Attribute attribute in info.GetCustomAttributes())
                {
                    if (attribute.GetType() == typeof(MaxLength))
                    {
                        MaxLength ml = attribute as MaxLength;
                        string oPropertyValue = info.GetValue(o) as string;
                        if (ml != null && oPropertyValue != null)
                        {
                            if (oPropertyValue.Length > ml.Length)
                            {
                                return false;
                            }
                        }
                    }
                }
            }

            return true;
        }
    }

    class Student
    {
        [MaxLength(3)] public string StudentName { get; set; }
    }

    class Program
    {
        static void Main()
        {
            Student student = new Student();
            student.StudentName = "Tommy";
            bool result = ValidateUtil.Valid(student);
            Console.WriteLine(result);
        }
    }
}

代码非常简单,我们自定义了一个MaxLength注解,[AttributeUsage(AttributeTargets.Property)]表示该注解可以标注在类的属性上。我们的自定义注解继承Attribute类,其内部维护了一个整数。

数据验证逻辑在ValidateUtil类中,代码通过反射获取一个对象的所有属性,并获取属性的注解。如果我们自定义注解存在,就比较属性值字符串长度和校验长度,如果不符合校验规则就返回false

作者:Gacfox
版权声明:本网站为非盈利性质,文章如非特殊说明均为原创,版权遵循知识共享协议CC BY-NC-ND 4.0进行授权,转载必须署名,禁止用于商业目的或演绎修改后转载。
Copyright © 2017-2024 Gacfox All Rights Reserved.
Build with NextJS | Sitemap