如何使用反射以递归方式检查嵌套对象的必需属性

时间:2016-07-08 17:17:43

标签: c# recursion reflection

以下是包含一些必需属性的类

public class Employee
{
    public EmployeeType employeeType {get; set;}
    public Description description {get; set;}
}

public class EmployeeType
{
    public NameType nameField {get; set;}
    public string Address {get; set;}
}

public class NameType 
{
    [Required]
    public string FirstName {get; set;}
    [Required]
    public string LastName {get; set;}
    public Role RoleType {get; set;}
}

public class Role 
{
    public int RoleId {get; set;}
    [Required]
    public string Name {get; set;}
}

public class Description
{
    [Required]
    public string ShortDesciption {get; set;}
    public string LongDescription {get; set;}
}

我编写了一个方法来对属性进行递归检查,但它没有通过必需的注释,并且在找到具有空值的第一个属性后它不会继续前进。

这是我的代码,

private List<string> GetNullOrEmptyPropertiesList(object myObject)
{
    List<string> lst = new List<string>();
    foreach (PropertyInfo pi in myObject.GetType().GetProperties())
    {
        if (pi.PropertyType == typeof(string))
        {
            string value = (string)pi.GetValue(myObject);
            if (string.IsNullOrEmpty(value))
            {
                if (pi.Name == "ShortDescription" || pi.Name == "FirstName")
                {
                    lst.Add(pi.Name);
                }
            }
         }

         else
         {
             var value = pi.GetValue(myObject);
             return GetNullOrEmptyPropertiesList(value);
         }
     }

     return lst;
 }

2 个答案:

答案 0 :(得分:0)

你并不是第一个做这样事情的人。 MVC有一种验证对象的方法,而无需进行反射。

我必须做一些代码生成,生成视图模型,生成验证规则并生成测试代码,以确保一切正常运行。

MVC有ModelState和IsValid来检查这些东西,所以允许你直接验证它是有意义的。

这是一个仅验证模型中一个属性的示例:

<Grid local:Window2.SvgProp="0x23">
            <Path Fill="Red" Data="M311.517,14.053c-99.265,0-180.024,80.66-180.024,179.805c0,41.538,14.182,79.827,37.955,110.303L0,451.176l22.889,26.313    l170.577-147.994c31.628,27.496,72.926,44.168,118.051,44.168c99.266,0,180.025-80.661,180.025-179.805    C491.542,94.713,410.784,14.053,311.517,14.053z M311.517,353.663c-88.237,0-160.024-71.688-160.024-159.805    S223.279,34.053,311.517,34.053s160.025,71.688,160.025,159.805S399.755,353.663,311.517,353.663z"/>                    
            <Polygon Points="322.447,122.812 300.587,122.812 300.587,182.928 240.471,182.928 240.471,204.788 300.587,204.788     300.587,264.904 322.447,264.904 322.447,204.788 382.563,204.788 382.563,182.928 322.447,182.928   " Fill="#000000"/>
 </Grid>

这里,模型是我要验证的类,MemberName是我要验证的属性,modelValue是该属性的数据。这将检查所有验证规则,就像MVC引擎一样。

如果你想验证整个模型,意味着不仅仅是一个属性,那么你可以使用类似的东西:

var context = new ValidationContext(model, serviceProvider: null, items: null);
            context.MemberName = "FirstName";

            var results = new List<ValidationResult>();
            var modelValue = "someValue";
            var isValid = Validator.TryValidateProperty(modelValue, context, results);

最后要特别注意真实参数。它说基本上验证了我的所有财产。

答案 1 :(得分:0)

以下是您可以做您想做的事情:

private static List<string> GetNullOrEmptyPropertiesList(object myObject)
{
    var list = new List<string>();
    AddNullOrEmptyProperties(myObject, list);
    return list;
}

private static void AddNullOrEmptyProperties(object myObject, List<string> list, string path = null)
{
    if (myObject == null) return;
    var type = myObject.GetType();
    if (type.IsPrimitive || type == typeof(string)) return;
    foreach (var pi in myObject.GetType().GetProperties())
    {
        if (!pi.CanRead || pi.GetIndexParameters().Length > 0) continue;
        var name = path != null ? path + "." + pi.Name : pi.Name;
        var value = pi.GetValue(myObject);
        if (pi.IsDefined(typeof(RequiredAttribute)) && (value == null || (value as string) == string.Empty))
            list.Add(name);
        AddNullOrEmptyProperties(value, list, name);
    }
}

一些注意事项:

  • 无论何时需要递归填充某些列表,最好将递归部分与非递归部分分开。在非递归部分中,您只需分配列表并调用传递已分配列表的递归部分以及所需的任何其他参数。

  • 检查特定属性是否存在的最简单方法是使用某些IsDefined方法。