You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C#泛型类获取带自定义Step属性的模型属性集合

实现方案:泛型类获取带StepAttribute的属性集合

这事儿用反射就能轻松搞定!我们可以写一个泛型类,通过.NET的反射机制遍历目标模型的属性,筛选出标记了StepAttribute的属性,甚至可以按StepName进行分组查询。下面是完整的实现方案:

1. 优化你的StepAttribute(可选,但更规范)

你原来的StepAttribute可以简化成自动属性,还可以加个带参数的构造函数,标记属性时会更简洁:

public class StepAttribute : Attribute
{
    public string StepName { get; set; }

    // 可选:添加带参数的构造函数,直接指定StepName
    public StepAttribute(string stepName)
    {
        StepName = stepName;
    }
}

这样你的模型可以写成更简洁的形式:

public class MobileKeyViewData
{ 
    [Step("PersonalData")] 
    public int PhoneNumber { get; set; } 
    [Step("PersonalData")] 
    public string Email { get; set; } 
    [Step("Confirmation")] 
    public int Code { get; set; } 
}

2. 泛型类核心实现

这个泛型类提供了两个核心方法:获取所有带StepAttribute的属性,以及根据指定StepName过滤属性:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;

public class StepPropertyHelper<T> where T : class
{
    /// <summary>
    /// 获取模型中所有标记了StepAttribute的属性
    /// </summary>
    /// <returns>带StepAttribute的属性集合</returns>
    public static IEnumerable<PropertyInfo> GetAllStepProperties()
    {
        var modelType = typeof(T);
        // 只获取公共实例属性(符合你的模型属性定义)
        return modelType.GetProperties(BindingFlags.Public | BindingFlags.Instance)
            .Where(prop => Attribute.IsDefined(prop, typeof(StepAttribute)))
            .ToList();
    }

    /// <summary>
    /// 根据指定的StepName获取对应属性集合
    /// </summary>
    /// <param name="stepName">要筛选的步骤名称</param>
    /// <returns>对应步骤下的属性集合</returns>
    /// <exception cref="ArgumentNullException">当stepName为空时抛出</exception>
    public static IEnumerable<PropertyInfo> GetPropertiesByStepName(string stepName)
    {
        if (string.IsNullOrWhiteSpace(stepName))
            throw new ArgumentNullException(nameof(stepName), "步骤名称不能为空");

        return GetAllStepProperties()
            .Where(prop => 
            {
                var stepAttr = prop.GetCustomAttribute<StepAttribute>();
                // 这里用忽略大小写的比较,你可以根据需求改成精确匹配
                return stepAttr != null && stepAttr.StepName.Equals(stepName, StringComparison.OrdinalIgnoreCase);
            })
            .ToList();
    }
}

3. 使用示例

针对你的MobileKeyViewData模型,这样调用即可:

// 获取所有带StepAttribute的属性
var allStepProperties = StepPropertyHelper<MobileKeyViewData>.GetAllStepProperties();
foreach (var prop in allStepProperties)
{
    var stepAttr = prop.GetCustomAttribute<StepAttribute>();
    Console.WriteLine($"属性:{prop.Name},类型:{prop.PropertyType.Name},所属步骤:{stepAttr.StepName}");
}

// 获取"PersonalData"步骤下的属性
var personalDataProps = StepPropertyHelper<MobileKeyViewData>.GetPropertiesByStepName("PersonalData");
foreach (var prop in personalDataProps)
{
    Console.WriteLine($"PersonalData步骤的属性:{prop.Name}");
}

4. 进阶:返回封装后的属性信息(可选)

如果需要更友好的返回结果,可以创建一个DTO类来封装属性的关键信息:

public class StepPropertyDetail
{
    public string PropertyName { get; set; }
    public Type PropertyType { get; set; }
    public string StepName { get; set; }
}

然后修改泛型类的方法,返回这个DTO集合:

public static IEnumerable<StepPropertyDetail> GetAllStepPropertyDetails()
{
    var modelType = typeof(T);
    return modelType.GetProperties(BindingFlags.Public | BindingFlags.Instance)
        .Where(prop => Attribute.IsDefined(prop, typeof(StepAttribute)))
        .Select(prop => new StepPropertyDetail
        {
            PropertyName = prop.Name,
            PropertyType = prop.PropertyType,
            StepName = prop.GetCustomAttribute<StepAttribute>().StepName
        })
        .ToList();
}

这样调用时就能直接拿到结构化的信息,不用再手动获取属性特性了。


内容的提问来源于stack exchange,提问作者Fabio Santos

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 10:19:47