是否存在验证用户输入的最佳实践方法
本文关键字:最佳 方法 输入 存在 验证 用户 是否 | 更新日期: 2023-09-27 18:04:16
是否有最佳实践方法验证用户输入?
实际问题:用户在窗口中输入特定的内容。当他完成这些输入后,他可以点击"创建"。现在,应该显示一个弹出消息,其中给出了所有无效的输入。如果没有无效输入,则继续。
我可以很容易地在Form类中做到这一点。但我记得验证集合属性中的输入的一些最佳实践方法。问题是,如果我以这种方式验证,我已经创建了该类的实例(否则,不能设置属性;))。这是不应该发生的,除非输入是有效的,否则不能创建类的实例。我计划创建一个ErrorMessages类,它包含一个列表,我可以把所有的ErrorMessages。每次给出无效输入时,都会向errorMessages列表中添加一条新消息。所以如果用户点击'create'按钮,列表中的所有消息都会显示出来。这是处理事情的好方法吗?
那么有没有最佳实践方法呢?有没有提供这种解决方案的设计模式?
Edit:这是学校的任务。所以对于不合逻辑的要求。当我点击"创建"时,我必须显示所有无效的输入。我想在表单课之外做这个。(因此,即使没有GUI,验证也可以工作,此时我甚至还没有创建GUI)。首先确保我的功能正常工作;)。我想保持我的代码干净、抽象和面向对象。那么我应该如何显示错误消息呢?
我计划创建一个ErrorMessages类,它包含一个列表,我可以把所有的ErrorMessages。每次给出无效输入时,都会向errorMessages列表中添加一条新消息。所以如果用户点击'create'按钮,列表中的所有消息都会显示出来。这是处理事情的好方法吗?
主观上,我认为最好提供即时反馈,用户输入的值无效。这样,他们就可以立即回去修复它。
我的意思是,想想看。您提出的方法实际上会在最后给他们一个巨大的问题列表,这不是很友好。此外,他们如何记住所有这些问题,以便能够回去一次解决一个问题?(提示:他们不是。)
相反,我建议使用ErrorProvider
类在适当控件旁边显示任何错误。关于这种方法,我在这里和这里的回答中多谈了一点。
当然,您仍然需要确保在最终提交时(单击OK/Submit按钮)所有输入都是有效的,但这只是检查是否存在任何错误的简单情况。
我可以很容易地在Form类中做到这一点。但我记得验证集合属性中的输入的一些最佳实践方法。
是的,这里的思想是封装。Form类应该只知道Form的东西。不应该要求知道哪种输入对所有不同的控件有效/无效。
相反,这个验证逻辑应该放在其他地方,比如存储数据的类中。该类将公开公共属性以获取和设置数据,并在setter方法内部验证数据。
这意味着所有你的表单必须做的是调用一个setter方法在你的数据类。表单不需要知道如何验证数据,甚至不需要知道数据的含义,因为数据类处理所有这些。
这是不应该发生的,除非输入是有效的,否则不能创建类的实例。
如果确实是这种情况,则需要为类提供一个构造函数,该构造函数接受所需的所有数据作为参数。然后,构造函数体将验证指定的数据,如果其中任何数据无效,则抛出异常。该异常将阻止创建类,确保不存在包含无效数据的类实例。
这样的类可能根本没有setter方法——只有getter方法。
然而,这在c#世界中是一种不寻常的要求(无论它在c++中多么常见)。一般来说,将验证代码放在setter中就可以了。
我的属性有一些私有的设置。它们只能在data类的构造函数中设置。现在的问题是,这似乎使我的验证不容易
为什么会改变什么呢?您仍然在私有setter内部处理验证。如果验证失败,则抛出异常。因为构造函数不处理异常,所以它继续从该方法冒泡到试图实例化对象的代码中。如果该代码想要处理异常(例如,向用户显示错误消息),它可以这样做。
当然,在无效输入的情况下抛出异常不一定是"最佳实践"。原因是异常通常应该为意外情况保留,用户搞砸并向您提供无效数据是意料之中的事情。然而:
- 这是你在构造函数内部进行数据验证的唯一选择,因为构造函数不能返回值。
- 异常处理的成本在UI代码中基本上可以忽略不计,因为现代计算机处理异常的速度比用户感知屏幕变化的速度要快。
这是一个简单的要求,但有时会引起争论。这是我处理验证的"当前"方法。我还没有使用过这种方法,这只是一个概念。这种方法需要进一步发展
首先,创建一个自定义验证属性public class ValidationAttribute : Attribute{
public type RuleType{get;set;}
public string Rule{get;set;}
public string[] RuleValue{get;set;}
}
其次,创建自定义错误处理程序/消息
public class ValidationResult{
public bool IsSuccess{get;set;};
public string[] ErrorMessages{get;set;};
}
然后创建一个验证器
public class RuleValidator{
public ValidationResult Validate(object o){
ValidationResult result = new ValidationResult();
List<string> validationErrors = new List<string>();
PropertyInfo[] properties = o.GetType().GetProperties();
foreach(PropertyInfo prop in properties){
// validate here
// if error occur{
validationErrors.Add(string.Format("ErrorMessage at {0}", prop.Name));
//}
}
result.ErrorMessages = validationErrors.ToArray();
}
}
要使用它,你可以这样做:
public class Person{
[ValidationAttribute(typeof(string), "Required", "true")]
public string Name{get;set;}
[ValidationAttribute(typeof(int), "Min", "1")]
public int Age{get;set;}
}
调用验证器
public void ValidatePerson(Person person){
RuleValidator validator = new RuleValidator();
ValidationResult result = validator.Validate(person);
// generate the error message here, use result.ErrorMessages as source
}
优势是什么:
- 您可以在任何应用程序平台(Winforms, Asp。净,WCF,等)
- 可以在attribute-level 中设置规则
- 可以自动验证
- 这个方法可以和DependencyInjection一起使用分隔验证逻辑的验证器
的劣势:
- 难以创建验证器
- 如果处理不好,验证器的数量会变得非常大
- 由于使用反射导致性能差
参见ErrorProvider
类(这里的文档)。它提供了一组标准的可视指示器,可以附加到大多数标准的WinForms控件上。
有几种可能的方法:
- 使用"即时"验证
当用户输入值时,在输入(TextChanged
)期间检查并立即验证。创建一个新类的实例,调用属性/方法应该接受string
并返回bool
(或抛出Exception
在属性的情况下),在false
-绘制特殊的错误条件(文本框旁边的红色标签,闪烁的东西,ErrorProvider
或任何你能做的应该告诉用户"错误!")。
这个我喜欢使用,但有点不同,通常我只检查Type
,然后只是试图直接解析它的形式。如果表单与string
操作,并且所有格式化和验证都发生在类(属性设置器)中,则可以抽象更多。或者您可以为表单提供附加信息(通过使用查询方法或属性),这样它就可以进行即时验证,而无需实例化类或使用setter。例如,double factor
属性可以在表单(甚至控件)中标识为执行'double '。解析and you can have attribute
DefaultValue which can be used to display to the user value in the different way when it's different from default (like it is done by
PropertyGrid
- 使用正常验证
当用户完成输入时,验证(通过尝试设置值并捕获异常),如果错误-用户不能"离开"或"进度",直到按ESC(取消更改)或纠正输入以通过验证。
这个我不喜欢。持有用户的想法惹恼了我(和用户ofc)。而且很难实现交叉检查(比如如果你有Min
和Max
的值,那么用户将被要求先增加"右"一个,否则无效将失败)。
- 使用"ok"验证
这只是意味着让用户输入所有内容,只有当他点击"确定"按钮时才验证。
我认为结合"Ok"按钮和交互式即时验证对用户来说是最好的。由于用户知道他在输入中犯了错误,但仍然可以自由浏览,只有在点击"确定"按钮后才会从验证中得到一个"耳光"(在这个步骤中,你可以简单地向他展示他所犯的第一个错误,而不必显示所有错误)。
错误信息可以由设置器以老式的LastError
方式提供,也可以作为Exception
中的文本提供。