【问题标题】:a basic issue in implementing validations through properties ? Please guide me通过属性实现验证的基本问题?请指导我
【发布时间】:2025-12-26 15:30:06
【问题描述】:

感谢您的关注和时间。

我想在属性的 settter 中实现验证。这是一个需要您的专家帮助的问题。

我知道在设置值之前我将如何进行验证。但如果传递的值不正确,则不知道该怎么做。只是不设置不是一个可接受的解决方案,因为我想向用户返回适当的消息(在 Web 表单的标签中)。我的示例代码是:

private  int id;
public int Id
{
    get
    { return id; }

    set
    {
        bool result = IsNumber(value);
        if (result==false)
        {
            // What to do if passed data is not valid ? how to give a appropriate message to user that what is wrong ?
        }

        id = value;
    }
}

一个想法是使用return,但这是不允许的。

抛出错误看起来不太好,因为我们通常会避免抛出自定义错误。

请指导和帮助我。

感谢期待

汉斯

【问题讨论】:

  • "result==false",你为什么需要比较两个布尔值然后决定行动?为什么不简单地“if(!result)”,变量名也应该表达它所持有的值的上下文和含义。
  • 不确定你的 IsNumber 方法是做什么的,但因为它是一个 int 属性的集合,所以这总是正确的。
  • 感谢@Amby 和@Rob van Groenewoud,我只是以这段代码为例。您能否就我的问题提出建议,即如果值无效,如何向用户界面发送指示?谢谢朋友

标签: c# asp.net validation fluentvalidation fluentvalidation-2.0


【解决方案1】:

您可以考虑从属性设置器中抛出适当的异常。这样一来,调用方就会清楚出了什么问题,尤其是假设您有关于设置属性的业务规则。当然,您确实希望调用者进行验证,如果仍然存在问题,那么抛出异常似乎并没有那么糟糕。

“从属性设置器抛出异常是有效且可接受的。” Property design guidelines

Best practices: throwing exceptions from properties

What exception to throw from a property setter?

【讨论】:

    【解决方案2】:

    我认为你最好换个例子,因为:

    public int Id
    {
      get { ... }
      set 
      { 
          if (!IsNumer(value)) // changes to if (value>5)
          {
                //the code here will never be executed
               id = value;
          }
      }
    }
    

    【讨论】:

    • 这似乎很危险。属性不能在不发出警报的情况下做出决定,这种代码很难调试。
    • @Amby 你是绝对正确的。我对你的问题提出这个答案。事实上,我认为在分配时检查值不是一个好主意。所有的验证都应该放在一个地方。
    【解决方案3】:
    1. 如果检查只是关于数字(类型),那么您的财产可以很好地处理类型安全。例如。用户将无法将字符串分配给接受 int 的属性。

    2. 我建议如果 Property 涉及某些计算,那么应该考虑使用一种方法。在这种情况下,您可以选择获取一些文本作为回报。

    3. 另一种选择是将所有这些验证检查存储在一个实例集合中(在同一个对象内)。喜欢。

      私有列表_faileValdations;

    //更多代码

        set
        {
        if (!IsNumber(value))
        {
        _faileValdations.Add("Invalid value for xxx. Expected... got..");
        }
        else{
            id = value;
        }
        }
    

    然后,您的 GUI 可以最终读取 FailedValidations 集合,并将其以格式化的方式显示在某个标签中。

    编辑:下面还有一个选项。

    1. 抱歉,我之前忘了提这个。

    您也可以使用事件驱动的方法。 您的对象可以公开类似“ValidationFailed”的事件,并且所有 GUI 对象都可以订阅此事件。如果 setter 中的任何验证失败,该对象将触发此事件。

        set {
        if (!IsNumber(value))
        {
        RaiseValidationFailed("some message");
        }
        else{
            id = value;
        }
        }
    

    “RaiseValidationFailed”可以收集消息,将其包裹在一些事件参数中,并与消息一起触发“ValidationFailed”事件。然后 GUI 可以对此做出反应。 {如果不清楚,我可以为您提供完整的代码}

    【讨论】:

    • 非常感谢 Amby,验证包括(类型和计算)。我想从 setter 实现它,因为每次填充对象时都会自动调用它,但需要调用方法。通过使用列表来保存所有验证消息可能是最后的解决方案,因为它会使它有点复杂。任何建议请感谢您的建议和宝贵的时间。
    • @haansi,不太清楚您所说的“因为每次填充对象时都会自动调用它”是什么意思。只要它是您的对象,您就可以决定用户将如何与您的对象进行交互。如果您只公开设置值的方法,那么客户端将无法逃避它。
    【解决方案4】:

    我认为您应该重新考虑您的验证方法。您建议的方法意味着每次属性更改时都会生成一条消息。

    如何收集、存储和呈现这些消息?特别是如果您决定在网站上使用您的课程?

    如果您想在其他时间验证您的课程怎么办?

    如果您想在客户端验证中使用相同的规则怎么办?

    我可以理解尽早捕获无效值的吸引力,但是在一次调用(例如 Validate() 方法)中验证整个类要容易得多。这样,您就可以完全控制验证逻辑的运行时间。

    我建议您阅读两种主要的属性验证方法:

    Data Anotations

    Fluent Validation for >NET 3.0 and above

    Fluent Validation for .NET 2.0

    Data Annotations 和 FluentValidation 都易于使用,它们能够在 Web 表单和 win 表单上生成经过良好测试的客户端验证。

    在数据注释中,使用属性将验证添加到属性中。如果您希望将数据类保持为干净的数据传输对象,Fluent 验证涉及在 Validator 类中创建易于阅读的规则。

    【讨论】: