我有一个关于何时验证C#表单应用程序输入的问题。
从表单应用程序获取输入时,您可以在解析主表单类中的文本字段中的数据时运行所有验证,然后在任何地方使用。例如:
方法1:
class Car
{
private string registration { set; get; } // NO VALIDATION HERE
}
// in the form class
private void add_Click(object sender, EventArgs e)
{
// get registration
int reg_valid = Validate.registration(txtReg.Text); // VALIDATION IS DONE HERE
if(reg_valid)
{
Car.registration = txtReg.Text;
} else {
// Registration invalid - throw error
}
}
实际的Car对象中没有验证,因为它都是在表单类中完成的。
另一种方法是验证存储在其中的实际类中的输入,如:
方法2:
class Car
{
// out registration
private string registration;
// we can set our registration here and return false if there is an error
bool set_registration(registration)
{
int reg_valid = Validate.registration(registration); // VALIDATION IS DONE HERE
if(reg_valid) {
this.registration = registration;
} else {
return false; // if error
}
return true; // if all goes well
}
}
// in the form class
private void add_Click(object sender, EventArgs e)
{
// get registration
string registration = txtReg.Text; // NO VALIDATION DONE HERE
// we can then store this in our object
if( ! Car.set_registration(registration))
{
// Registration invalid - throw error
}
}
方法1看起来更干净,但我们使用私有属性的原因之一是我们可以验证任何解析参数,这就是为什么方法2似乎是更好的选择。此外,使用方法2,错误必须在堆栈中可能多次执行,这导致重复的if语句。
*请注意,此代码尚未运行,因此可能包含错误。
答案 0 :(得分:2)
您应该有一个 Core 类以及与用户界面相关的那些类。首先,创建应用程序的Core类(商务逻辑)。当然,你应该在这里做验证。实际上,代码就像你不知道谁将实现用户界面一样。此外,请考虑用户界面可以更改,而核心类应保持不变。
编写用户界面时,您会意识到如果您不进行任何验证,则在用户输入某些数据案例时会引发异常。这将使您在用户界面类中也创建验证。
所以,答案是,您最终将对应用程序的两个部分进行验证。
答案 1 :(得分:1)
警告:基于意见的回答!
这取决于项目的要求,比例,以及时间(以及许多其他重要因素,如< em>&#34;用户友好的应用程序&#34; 或者不重要,比如&#34;我自己的品味将是......&#34; )
由于每个人可能出现范围广泛,答案无法在一般指南中表达,这将满足每个人的需求
你的问题解决了两个要操纵的对象:
您有没时间,要求只是告诉&#34;输入一个值&#34;,这是一个小任务在项目中没有关键对于此Button中使用的小班级的重要性,你非常懒惰:
=&GT;在按钮单击中,使用一个或两个禁止检查来进行严格验证,这些检查会删除任何不允许的值,并根据错误的性质显示MessageBox。只有将值传递给类,并在有有效值时更进一步。
您没有时间,简单要求,小任务并不重要,但类主要使用,但您和#39;懒惰:
=&GT;将验证移到类上面,然后使用自定义消息抛出一个,两个或三个常规异常。在使用该类的任何UI操作中,使用Try / Catch捕获ButtonClick中的异常,并在捕获的异常情况下显示MessageBox而不会进一步。
您有 5分钟,简单要求,小型非关键任务,重要类角色:
=&GT;像以前一样,但是,决定是否更推荐显示用户的另一种方式(取决于您的目标用户),例如在单击按钮后更改TextBox的背景颜色,在Label中显示消息,而不是通过对话框使用户烦恼框...
您有 10分钟,简单要求,重复性任务,重要班级角色:
=&GT;找到一种快速测试给定值的方法,并在类中创建一个公共或朋友(静态?)函数,它返回验证尝试的结果,如UICarValidationEnum
枚举(*参见编辑下面的可能的验证错误:
a)UICarValidationEnum.Valid
b).TooLong
c).NullValue
d).ForbiddenChars
e)...
然后,您可以使用该验证功能内部和外部您的类。这样,您可以在执行Setter 之前处理无效的Setter尝试,并在执行时处理,以及使用类和UI 并且的没有即可。缺点是,如果检查数据是否在课堂外有效(例如,在按钮中),则无法避免双重验证。
时间很重要,但要求是高效输入,重复非常重要的任务,等级 强> - 你不能懒惰:
=&GT;处理UI验证和类验证。为什么? UI部分解决了&#34;高效输入&#34; part,Class Part解决了Class&#34;的作用。您可以使用上面的验证器函数,或者在上面的其他情况下在Setter上实现更多的异常。您通过在按钮点击时向用户提供更多信息,来增加处理的例外/无效输入的数量。
记住:类很常用。这里的举措是实现最大编码来处理无效输入的不同情况,以减少在项目中编写的代码量,同时仍然能够处理所有这些情况。
时间很重要,用户友好应用,重复性任务,重要类:
=&GT;重新考虑UI布局和行为,验证主要是UI,但Class仍在自行完成:
a)用户讨厌对话框(无论是DialogBox,消息,openfile等等......尽可能避免使用它们)
b)用户讨厌侵略性颜色
c)用户讨厌验证
d)......用户讨厌很多东西..!
上面的函数验证的作用非常重要:捕获用户输入操作。例如,如果它是TextBox,则捕获TextChanged事件,然后调用类验证函数。更新标签中的信息,通知任何遇到的错误,并将TextBox的背景颜色更改为友好颜色,但与错误标准相关,如浅粉红色。不要使用Color.Red,这对大多数用户来说过于激进。每天看200次红色可能会在一天结束时导致意外行为 仅在 ALL 输入有效时启用按钮。不要为每个输入创建一个按钮,用户讨厌无休止的验证。
时间并不重要,用户友好应用,重复任务,重要班级:
=&GT;与之前的选项一起,改善UI响应 在标签中添加图形图标,和/或考虑在表单中使用ErrorProvider。用户喜欢简单的图标,而不是长长的类似信息 考虑使用友好的声音来通知弹出错误(不是每个人都是&#34;有点视觉接受&#34; )
时间根本不重要,用户友好应用,重复任务,重要强>等级:
=&GT;继续实时捕获用户输入,但实施与之相关的暗示性更正。如果它是TextBox,当用户尝试输入无效数据时,请在集合中使用带有预定义和固定输入建议的AutoCompleteCollection(您需要一个功能)。
当与用户的选择/操作不兼容时,实时禁用其他输入。
时间非常重要,用户友好推荐,重复任务,重要类:
=&GT;不要使用验证程序重载表单
为该特定输入创建Custom Control
。使用验证超载自定义控件。如果您的课程无法在此用户界面之外使用,请不要在内部创建验证。移动自定义控件中的所有内容,甚至禁止无效字符(如果它是文本框)。在这种特定情况下,您将使用UserControl作为数据的Validator组件。
否则,在输入时使用类验证函数方案,并尽可能通过该用户控件以用户友好的方式显示相应的错误(在没有UserControl的情况下可以使用您的类的情况,通常是这种情况)
我知道我更多地考虑使用应用程序的用户而不是要编写代码的用户。但请看Baltasarq's answer。事实上,最好的举措就是两者兼而有之。这三个第一选项只适用于整个项目中的一个简单的,没有真正的重要性。我们所有人都创建了这个小类,我们并不打算做出强有力的验证控制。我认为我们大多数人仍然使用这类课程。然而,随着时间的推移,这些类的一些越来越多地被使用..然后我们面临着更强的验证方案的需要。
偷工减料方式。它不安全,但它有效......直到某事发生......
=&GT;尽可能尝试两者兼顾。你不知道会发生什么,谁会使用你的班级,你的老板是否会改变主意,并要求你为该班级创建一个特定的用户界面,以便每个人都能使用...
有一段时间,当我有时间创建一个班级时,我实际上就是这样 创建至少两个类:
- MyClass_Class
- MyClass_Form
- (也许 MyClass_UserControl )
- (也许 MyChildClass WithUnsafeSetters - 用于设置已根据性能需求验证的值)
核心类始终提供实时验证功能......
使用枚举的属性验证器函数示例...
[Flags]
public enum registrationValidation_Enum
{
Valid = 0x01,
TooLong = 0x02,
InvalidChars = 0x04,
NullEntry = 0x08
// ...
}
这个枚举可以封装在类中。枚举比异常类更容易处理/记忆/检索。
这是Property Getter / Setter。
class Car
{
private string registration = "Unknown";
public string Registration
{
get
{
return registration;
}
set
{
validate_registration(value, True);
// Setter for the Property.
// Throws an Exception upon invalid value.
}
}
}
这是一个公共验证函数:
public registrationValidation_Enum test_registration(
string newRegistration)
{
registrationValidation_Enum checkResult =
registrationValidation_Enum.Valid;
// Do the checks here
if (newRegistration.Length > 10)
{
checkResult = checkResult | registrationValidation_Enum.TooLong;
}
if (containsNonAlphNumericChars(newRegistration))
{
checkResult = checkResult | registrationValidation_Enum.InvalidChars;
}
// ...
return checkResult;
}
以下是Setter的公开版本:
// this bypass the double check : attempts to set the value if Valid.
// otherwise, either returns a validation result,
// either throws an exception.
public registrationValidation_Enum validate_registration(
string newRegistration,
bool canThrowException)
{
bool isValid = test_registration(newRegistration);
if (isValid == registrationValidation_Enum.Valid)
{
registration = newRegistration;
return registrationValidation_Enum.Valid;
}
else
{
if (canThrowException)
{
string exceptionMessage = "";
if (isValid | registrationValidation_Enum.TooLong)
{
exceptionMessage += "Registration too long"
+ Environment.NewLine;
}
if (isValid | registrationValidation_Enum.InvalidChars)
{
exceptionMessage +=
"Registration contains invalid characters"
+ Environment.NewLine;
}
// ....
Throw New Exception(exceptionMessage);
}
else
{
return isValid;
}
}
}
公开 validate_registration(string, false)
有以下情况:
将验证结果放在任何UI端的变量中,并根据您可以显示的UI组件显示相应的通知/用户选择...这不会像Exceptions那样简单:想象一下,你有TooLong和InvalidChars。你打算展示一个对话框&#34; Too Long&#34;然后单击按钮,然后显示另一个&#34;无效的字符&#34;对话?
注意:要使用使用Culture的自定义异常消息创建类可本地化,我将定义类级别消息(字符串)变量,其值取决于加载的文化。
答案 2 :(得分:0)
您可以将公共属性与私有成员一起使用,您可以在属性中进行检查,然后将其分配给类成员。
class Car
{
private string registration;
public string Registration
{
get { return registration;}
set {
if(Validate.registration(value))
registration = value;
else
throw new Exception("Your exception message here");
}
}
}
private void add_Click(object sender, EventArgs e)
{
Car.Registration = txtReg.Text;
}
答案 3 :(得分:0)
有2种验证:
看看PropertyGrid
。它的基本(并且相当充分)验证是你的财产接受价值还是抛出:
class Car
{
private int _someValue;
public int SomeValue
{
get { return _someValue; }
set
{
if(value > 100)
throw new OutOfRangeException(...);
_someValue = value;
}
}
}
这确保了Car
可以验证自己的属性,无论它们如何设置(反序列化,PropertyGrid
,直接属性值,反射等)。
另一件事是一些逻辑验证,它不能在实例级别执行,或者你根本不关心它(让实例无异常地创建)。这个必须放入编辑器代码(用于创建实例的形式)。
至于我自己,在讨论TextBox
时,我更喜欢自定义MyTextBox
控件,它具有所有解析相关验证(方法GetDouble()
,{{1设置/查询它的可能性(属性GetInt()
,GetIntTime()
等)。