属性(Property)+ 反射(Reflection) 的实战案例
                           
天天向上
发布: 2025-04-19 10:12:52

原创
557 人浏览过

下面是一个完整的基于 属性(Property)+ 反射(Reflection) 的实战场景示例,我们将构建一个:

轻量级的数据模型校验框架
通过属性上的自定义特性(Attribute),结合反射自动扫描并验证字段是否符合规则(如非空、长度、范围等)。


示例功能目标

  • 使用属性定义实体类字段。
  • 自定义验证 Attribute:如 [Required][StringLength]
  • 通过反射自动校验这些属性。
  • 输出验证结果。

一、目录结构(类划分)

ValidationDemo/
│
├── Attributes/
│   ├── RequiredAttribute.cs
│   └── StringLengthAttribute.cs
│
├── Validators/
│   └── ObjectValidator.cs
│
├── Models/
│   └── User.cs
│
└── Program.cs

二、代码实现

✅ 1. 自定义验证特性

🔹 RequiredAttribute.cs

[AttributeUsage(AttributeTargets.Property)]
public class RequiredAttribute : Attribute
{
    public string ErrorMessage { get; set; }

    public RequiredAttribute(string errorMessage = "该字段是必填项")
    {
        ErrorMessage = errorMessage;
    }
}

🔹 StringLengthAttribute.cs

[AttributeUsage(AttributeTargets.Property)]
public class StringLengthAttribute : Attribute
{
    public int MaxLength { get; set; }
    public int MinLength { get; set; }
    public string ErrorMessage { get; set; }

    public StringLengthAttribute(int minLength = 0, int maxLength = int.MaxValue, string errorMessage = "长度不符合要求")
    {
        MinLength = minLength;
        MaxLength = maxLength;
        ErrorMessage = errorMessage;
    }
}

✅ 2. 定义实体模型

🔹 User.cs

using ValidationDemo.Attributes;

public class User
{
    [Required("用户名不能为空")]
    [StringLength(3, 20, "用户名长度应在3-20之间")]
    public string Username { get; set; }

    [StringLength(6, 100, "密码必须在6-100字符之间")]
    public string Password { get; set; }

    [Required("邮箱是必填项")]
    public string Email { get; set; }
}

✅ 3. 核心验证器

🔹 ObjectValidator.cs

using System.Reflection;
using ValidationDemo.Attributes;

public class ObjectValidator
{
    public static List<string> Validate(object obj)
    {
        var errors = new List<string>();

        if (obj == null) throw new ArgumentNullException(nameof(obj));

        Type type = obj.GetType();
        PropertyInfo[] props = type.GetProperties();

        foreach (var prop in props)
        {
            var value = prop.GetValue(obj);

            // Required 检查
            var requiredAttr = prop.GetCustomAttribute<RequiredAttribute>();
            if (requiredAttr != null && (value == null || string.IsNullOrWhiteSpace(value.ToString())))
            {
                errors.Add($"{prop.Name}: {requiredAttr.ErrorMessage}");
            }

            // StringLength 检查
            var stringLengthAttr = prop.GetCustomAttribute<StringLengthAttribute>();
            if (stringLengthAttr != null && value is string strVal)
            {
                if (strVal.Length < stringLengthAttr.MinLength || strVal.Length > stringLengthAttr.MaxLength)
                {
                    errors.Add($"{prop.Name}: {stringLengthAttr.ErrorMessage}");
                }
            }
        }

        return errors;
    }
}

✅ 4. 测试入口

🔹 Program.cs

using ValidationDemo.Models;
using ValidationDemo.Validators;

class Program
{
    static void Main()
    {
        var user = new User
        {
            Username = "Al",
            Password = "123", // 太短
            Email = "" // 必填为空
        };

        var results = ObjectValidator.Validate(user);

        if (results.Any())
        {
            Console.WriteLine("验证失败:");
            foreach (var error in results)
                Console.WriteLine($" - {error}");
        }
        else
        {
            Console.WriteLine("验证通过!");
        }
    }
}

输出示例

验证失败:
 - Username: 用户名长度应在3-20之间
 - Password: 密码必须在6-100字符之间
 - Email: 邮箱是必填项

技术点说明

技术应用
属性(Property)封装数据字段
特性(Attribute)描述属性的校验规则
反射(Reflection)获取属性信息和特性、读取值
实体模型校验封装成可复用的验证器

权威链接


拓展方向推荐

  • ✅ 支持更多特性如:RangeAttributeRegexAttribute
  • ✅ 将验证器封装为中间件,集成至 ASP.NET Core 中(表单校验)
  • ✅ 属性缓存 + 表达式树以提升性能(避免频繁反射)

更多详细内容请关注其他相关文章!

发表回复 0

Your email address will not be published. Required fields are marked *