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

3

我有一个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();

2
为什么不让每个类的ValidateObject实现,也运行其包含的所有子对象的ValidateObject呢? - juharr
3个回答

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派生的字段,验证它们以及其中递归的所有字段。


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

更加规范的做法是让层级中的每个类都重写 ValidateObject() 方法来验证其子对象:

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

等等。那么客户端只需在根对象上调用ValidateObject()即可。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接