2

我想看看您对检查新序列化对象值的有效方法的想法。

示例 我有一个已序列化为对象的 xml 文档,现在我想做值检查。我能想到的第一个也是最基本的想法是使用嵌套的 if 语句并检查每个属性,可以是从一个值检查它是否具有正确的 url 格式,到检查另一个属性值,它是一个日期,但使其在正确的范围等

所以我的问题是人们将如何检查对象中的所有值?类型检查并不重要,因为这已经被处理了,它更多地与值本身有关。它需要用于相当大的对象,这就是我不想使用嵌套 if 语句的原因。

编辑:

我想对给定对象中的所有属性实现完整的值验证。

我想检查它自己的值而不是它是否为空。如果我有,我想检查特定事物的值,一个具有许多属性的对象是字符串类型并命名为主页。

如果没有失败,我希望能够检查 URL 格式中的字符串是否正确。这只是同一对象中的一个示例,我可以检查日期是否在给定范围内,如果不是,我将返回 false 或某种形式的失败。

我正在使用 c# .net 4。

4

6 回答 6

2

尝试使用Fluent Validation,它是关注点分离并从您的对象中配置验证

于 2012-09-26T09:27:08.180 回答
1

我建议将 Automapper 与 ValueResolver 一起使用。您可以使用 autommaper 以一种非常优雅的方式将 XML 反序列化为对象,并使用 ValueResolver 检查您获得的值是否有效。

您可以使用基本 ValueResolver 检查 Null 或无效转换,以及一些 CustomResolver 检查您获得的值是否正确。它可能不是您正在寻找的东西,但我认为这是一种优雅的方式。

在这里查看:http: //dannydouglass.com/2010/11/06/simplify-using-xml-data-with-automapper-and-linqtoxml

于 2012-09-26T09:04:16.030 回答
1
public class Validator<T>
{
    List<Func<T,bool>> _verifiers = new List<Func<T, bool>>();

    public void AddPropertyValidator(Func<T, bool> propValidator) 
    {
        _verifiers.Add(propValidator);
    }

    public bool IsValid(T objectToValidate)
    {
         try {
         return _verifiers.All(pv => pv(objectToValidate));
         } catch(Exception) {
            return false;
         }
    }
}

class ExampleObject {
     public string Name {get; set;}
     public int BirthYear { get;set;}
}


public static void Main(string[] args) 
{
    var validator = new Validator<ExampleObject>();
    validator.AddPropertyValidator(o => !string.IsNullOrEmpty(o.Name));
    validator.AddPropertyValidator(o => o.BirthYear > 1900 && o.BirthYear < DateTime.Now.Year );
    validator.AddPropertyValidator(o => o.Name.Length > 3);

    validator.Validate(new ExampleObject());
}
于 2012-09-26T09:05:25.233 回答
0

我假设您的问题是:如何有效地检查我的对象是否有效?

如果是这样,那么您的对象只是从某个文本源反序列化并不重要。如果您的问题是在反序列化时检查对象以在发现错误时快速停止反序列化,那是另一个问题,您应该更新您的问题。

当涉及到 C# 和管理工具时,通常不会讨论有效地验证对象。原因是不管你怎么做都很快。更常见的是讨论如何以易于阅读和易于维护的方式进行检查。

由于您的问题关于效率的,因此这里有一些想法:

  • 如果要检查大量对象并且性能至关重要,则可能需要将对象更改为数据数组,以便以一致的方式检查它们。例子:

不要让 MyObject[] MyObjects 其中 MyObject 有很多属性,而是分解每个属性并将它们放入这样的数组中:

int[] MyFirstProperties
float[] MySecondProperties

这样,遍历列表并检查值的循环可以尽可能快,并且 CPU 缓存中不会有很多缓存未命中,因为您在内存中向前循环。请务必使用未实现为链表的常规数组或列表,因为这可能会产生大量缓存未命中。

  • 如果您不想将对象分解为属性数组,似乎最高速度并不重要,但几乎是最高速度。然后,最好的办法是将对象保存在串行数组中并执行以下操作:

.

bool wasOk = true;
foreach (MyObject obj in MyObjects)
{
    if (obj.MyFirstProperty == someBadValue)
    {
        wasOk = false;
        break;
    }
    if (obj.MySecondProperty == someOtherBadValue)
    {
        wasOk = false;
        break;
    }
}

这将检查所有对象的属性是否正常。我不确定你的情况到底是什么,但我认为你明白了。仅检查对象的属性时,速度已经很不错了。

如果您进行字符串比较,请确保在可能的情况下使用 x = y,而不是使用更复杂的字符串比较,因为 x = y 有一些快速退出,例如如果其中任何一个为空,则返回,如果内存地址是一样的,如果我没记错的话,字符串是相等的,还有一些更聪明的东西。对于任何阅读本文的 Java 人,不要在 Java中这样做!它有时会起作用,但并非总是如此。

如果我没有回答您的问题,您需要改进您的问题。

于 2012-09-26T09:04:12.803 回答
0

我不确定我是否理解你的问题的深度,但是,你不会做这样的事情吗?

public SomeClass
{
    private const string UrlValidatorRegex = "http://...

    private const DateTime MinValidSomeDate = ...
    private const DateTime MaxValidSomeDate = ...

    public string SomeUrl { get; set; }

    public DateTime SomeDate { get; set; }

    ...

    private ValidationResult ValidateProperties()
    {
        var urlValidator = new RegEx(urlValidatorRegex);
        if (!urlValidator.IsMatch(this.Someurl))
        {
            return new ValidationResult
                {
                    IsValid = false,
                    Message = "SomeUrl format invalid."
                };
        }

        if (this.SomeDate < MinValidSomeDate 
            || this.SomeDate > MinValidSomeDate)
        {
            return new ValidationResult
                {
                    IsValid = false,
                    Message = "SomeDate outside permitted bounds."
                };
        }

        ...
        // Check other fields and properties here, return false on failure.
        ...

        return new ValidationResult
                {
                    IsValid = true,
                };
    }

    ...

    private struct ValidationResult
    {
        public bool IsValid;
        public string Message;
    }
}

确切的验证代码会根据您希望班级的工作方式而有所不同,不是吗?考虑一个熟悉类型的属性,

public string SomeString { get; set; }

此属性的有效值是什么。两者都可能有效nullstring.Empty也可能无效,具体取决于Class装饰的财产。可能存在应该允许的最大长度,但是这些细节会因实现而异。


如果任何建议的答案比上面的代码更复杂而没有提高性能或功能,它会更有效吗?

实际上,您的问题是,如何在无需编写大量代码的情况下检查对象的值?

于 2012-09-26T08:56:35.400 回答
0

在 Haskell 等函数式语言中,可以使用 Maybe-monad 解决您的问题:

Maybe monad 体现了组合计算链的策略,如果任何步骤产生Nothing作为输出,每个计算链都可能通过提前结束链来返回Nothing 。当计算需要一系列相互依赖的步骤并且其中某些步骤可能无法返回值时,它很有用。

Nothing替换为null,同样的事情也适用于 C#。

有几种方法可以尝试解决这个问题,但都不是特别漂亮。如果你想要一个运行时验证某些东西不为空,你可以使用AOP 框架将空检查代码注入你的类型。否则你真的不得不做嵌套的 if 检查 null ,这不仅丑陋,而且可能违反Demeter 法则

作为一种折衷方案,您可以使用类似 Maybe-monad 的一组扩展方法,这将允许您查询对象,并选择在其中一个属性为空的情况下要做什么。

看看 Dmitri Nesteruk 的这篇文章:http: //www.codeproject.com/Articles/109026/Chained-null-checks-and-the-Maybe-monad

希望有帮助。

于 2012-09-26T09:06:06.573 回答