C#遍历对象层次结构以执行方法

时间:2012-12-12 14:44:05

标签: c#

我有一个Case对象,它本身包含许多对象(见下文),它们再次包含对象。

这些对象可以从BaseDto类继承,该类实现ValidateObject方法,该方法在当前对象上执行DataAnnotation验证器,从而返回验证错误,并累积到ValidationResult集合中。

我想将以下混乱的语法转换为可以遍历给定对象的对象层次结构的东西,并且对于实现ValidateObject的每个对象(及其子对象!),执行它。

我现在感觉有点陷入困境,所以我会感激任何想法。

cCase.ValidateObject() &
cCase.Object1.ValidateObject() &
cCase.Object2.ValidateObject() &
cCase.Object3.ValidateObject() &
cCase.Object3.ChildObject1.ValidateObject() &
cCase.Object3.ChildObject2.ValidateObject() &
cCase.Object3.ChildObject3.ValidateObject() &
cCase.Object3.ChildObject4.ValidateObject() &
cCase.Object3.ChildObject4.ChildChildObject1.ValidateObject() &
cCase.Object3.ChildObject5.ValidateObject() &
cCase.Object4.ValidateObject() &
cCase.Object4.ChildObject6.ValidateObject();

3 个答案:

答案 0 :(得分:0)

您需要使用反射来获取所有继承自BaseDto类的字段:

public abstract class BaseDto
{
    public abstract bool ValidateObject();
}

// Sample class without nested fields, requiring validation.
public class Case2 : BaseDto
{
    public override bool ValidateObject()
    {
        Console.WriteLine("Validated: " + ToString());
        return false;
    }
}

// Sample nested class with nested fields, requiring validation.
public class Case1 : BaseDto
{
    private Case2 Object1 = new Case2();
    private Case2 Object2 = new Case2();
    private Stream stream = new MemoryStream();

    public override bool ValidateObject()
    {
        Console.WriteLine("Validated: " + ToString());
        return true;
    }
}

public class Case : BaseDto
{
    private Case1 Object1 = new Case1();
    private Case2 Object2 = new Case2();
    // don't touch this field
    private Stream stream = new MemoryStream();
    private Case1 Object3 = new Case1();

    public override bool ValidateObject()
    {
        Console.WriteLine("Validated: " + ToString());
        return true;
    }

    public bool ValidateAll()
    {
        if (!ValidateObject()) return false;
        return ValidateAll(this);
    }

    private bool ValidateAll(object o)
    {
        foreach (FieldInfo fieldInfo in o.GetType().GetFields(BindingFlags.Instance |
               BindingFlags.NonPublic |
               BindingFlags.Public))
        {
            BaseDto current = fieldInfo.GetValue(o) as BaseDto;

            if(current != null)
            {
                bool result = current.ValidateObject();
                if(!result)
                {
                    return false;
                }
                return ValidateAll(current);
            }
        }

        return true;
    }
}

在根对象上调用ValidateAll()。在它内部遍历所有从BaseDto派生的字段,以递归方式验证它们及其中的所有字段。

答案 1 :(得分:0)

我会使用这样的扩展方法:

public interface IValidatable
{
    bool ValidateObject();
}

public static class ValidateExtensions
{
    public static bool ValidateAll(this IValidatable item)
    {
        if (!item.ValidateObject())
            return false;

        const BindingFlags flags = BindingFlags.GetProperty | BindingFlags.Instance | BindingFlags.Public;
        var type = item.GetType();
        var props = type.GetProperties(flags).Select(x => x.GetValue(item));
        var fields = type.GetFields(flags).Select(x => x.GetValue(item));
        return props
            .Concat(fields)
            .OfType<IValidatable>()
            .Select(x => x.ValidateAll())
            .All(x => x);
    }
}

答案 2 :(得分:-2)

让层次结构中的每个类重写ValidateObject()以验证其子对象会更清晰:

public override bool ValidateObject()
{
    return base.ValidateObject() & 
        this.Object1.ValidateObject() &
        this.Object2.ValidateObject() &
        this.Object3.ValidateObject() &
        this.Object4.ValidateObject();
}

等。然后客户端可以只调用根对象上的ValidateObject()