c#是否有更好的方法来验证用户输入
本文关键字:验证 用户 输入 方法 是否 更好 | 更新日期: 2023-09-27 18:30:01
我有以下代码:
private void btnOK_Click(object sender, EventArgs e)
{
if (!string.IsNullOrEmpty(tbVendorName.Text))
{
VendorName = tbVendorName.Text;
if (!string.IsNullOrEmpty(rtbVendorAddress.Text))
{
VendorAddress = rtbVendorAddress.Text;
if (!string.IsNullOrEmpty(tbVendorEmail.Text))
{
VendorEmail = tbVendorEmail.Text;
if (!string.IsNullOrEmpty(tbVendorWebsite.Text))
{
VendorWebsite = tbVendorWebsite.Text;
this.Close();
}
else
{
MessageBox.Show("Vendor Website Required");
}
}
else
{
MessageBox.Show("Vendor email is required");
}
}
else
{
MessageBox.Show("Vendor address is required");
}
}
else
{
MessageBox.Show("Vendor name is required");
}
}
但它看起来很可怕。有更好的方法吗?或者甚至是一种使代码更可读的替代方法?
更好的方法是掌握MVVM模式。在那里你可以创建一个ViewModel并定义所有输入数据:
class VendorViewModel
{
[Required]
public string Name { get; set; }
public string Website { get; set; }
[Regex("regex for email")]
public string Email { get; set; }
[MaxLength(160)]
public string Address { get; set; }
}
然后,框架将在每个文本框或任何其他输入元素之后显示输入错误(如果有的话)。按钮的启用属性将根据正确验证的所有字段自动设置。
将其放入一个方法中,并从该方法返回一个布尔值以判断是否有效。
private void btnOK_Click(object sender, EventArgs e)
{
if(!Validate())
{
//Invalid
}
//Valid so set details
}
private bool Validate()
{
if (!string.IsNullOrEmpty(tbVendorName.Text))
{
MessageBox.Show(...);
return false;
}
return true;
}
我会为这个任务构建一个这样的专用方法:
private bool ValidateInput()
{
bool ret = true;
// List all the inputs you want, add a description for each one
List<KeyValuePair<<string,string>) inputs = new Dictionary<string,string>();
inputs.Add(new KeyValuePair<string,string>(tbVendorName.Text, "Vendor Name"));
inputs.Add(new KeyValuePair<string,string>(tbVendorAddress.Text, "Vendor Address"));
// .. and so on and so forth
// Build a list of the empty ones
if(inputs.Any(i => string.IsNullOrEmpty(i.Key))
{
var msg = string.Join(", ", inputs.Where(i => string.IsNullOrEmpty(i.Key));
MessageBox.Show(string.Format("The following inputs are required: {0}", msg);
ret = false;
}
return ret;
}
阅读起来很容易,而且很清楚这个方法的作用,同时非常紧凑。此外,如果需要,字段列表可能会从方法中移出,并成为一个类字段(只需将列表作为参数传递,就可以了)。许多方法在这里都是合理的。
用法:
private void btnOK_Click(object sender, EventArgs e)
{
if (ValidateInput())
{
// They're all filled!
}
else
{
// Something was missing.
}
}
我在这里的答案中没有看到过一种模式,也是我喜欢的模式,那就是使用yield return
进行验证。它不像基于属性的验证那样干净,但它很容易根据许多场景进行自定义,并且适用于WinForms
项目。
它还同时返回所有错误,而不是一次只返回一个错误。
private void btnOK_Click(object sender, EventArgs e)
{
var errors = Validate();
if (errors.Any())
{
var sb = new StringBuilder();
sb.AppendLine("The following errors were found:");
foreach (var error in errors)
{
sb.AppendLine(error);
}
MessageBox.Show(sb.ToString());
return;
}
}
private IEnumerable<string> Validate()
{
if (string.IsNullOrEmpty(tbVendorName.Text))
{
yield return "Vendor name missing";
}
if (string.IsNullOrEmpty(rtbVendorAddress.Text))
{
yield return "Vendor address missing";
}
if (string.IsNullOrEmpty(tbVendorEmail.Text))
{
yield return "Vendor email missing";
}
}
如果一切都必须正常才能继续。你可以这样做:
private void btnOK_Click(object sender, EventArgs e)
{
if (!string.IsNullOrEmpty(tbVendorEmail.Text))
{
VendorEmail = tbVendorEmail.Text;
}
else
{
MessageBox.Show("Vendor email is required");
}
if (!string.IsNullOrEmpty(tbVendorName.Text))
{
VendorName = tbVendorName.Text;
}
else
{
MessageBox.Show("Vendor name is required");
}
if (!string.IsNullOrEmpty(rtbVendorAddress.Text))
{
VendorAddress = rtbVendorAddress.Text;
}
else
{
MessageBox.Show("Vendor address is required");
}
if (!string.IsNullOrEmpty(tbVendorWebsite.Text))
{
VendorWebsite = tbVendorWebsite.Text;
this.Close();
}
else
{
MessageBox.Show("Vendor Website Required");
}
}
不知道这是什么。Close可以,但您可以使用布尔值来检查是否必须关闭它。类似:
If(boolean=true)
{
this.Close();
}
然后在一切正常时将布尔值设置为true
肯定有更简单的方法,但我不知道怎么做。
我认为用户输入验证应该使用文本框或其他控件旁边出现的工具提示来完成,只要这些控件没有焦点。有很多验证框架。如果你在这里使用简单的WPF,一个很好的例子:http://www.codeproject.com/Articles/15239/Validation-in-Windows-Presentation-Foundation对于带有MVVM的WPF:http://www.codeproject.com/Articles/97564/Attributes-based-Validation-in-a-WPF-MVVM-Applicat对于Win表单,请查看以下内容http://www.codeproject.com/Articles/10093/Validators-for-Windows-Forms-ValidationProvider-Co
如果要使用常规if
,可以使用LINQ扩展方法:
bool valid = new [] { tbVendorName, rtbVendorAddress, tbVendorEmail, tbVendorWebsite }
.All(textBox => !string.IsNullOrEmpty(textBox.Text));
if(valid)
{
VendorName = tbVendorName.Text;
VendorAddress = rtbVendorAddress.Text;
VendorEmail = tbVendorEmail.Text;
VendorWebsite = tbVendorWebsite.Text;
}
.All(...)
扩展方法将确定对于IEnumerable<T>
中的所有项,整个布尔表达式是否为true。
此外,如果你想得到关于无效内容的准确结果,你可以使用规范模式:
public interface ISpecification<TObject>
{
// This holds the required field names
IList<string> RequiredFields { get; }
bool IsSatisfiedBy(TObject input);
}
public interface TextBoxSpecification : ISpecification<TextBox>
{
// This holds a relation between field names and their display name
private readonly IDictionary<string, string> _fieldMapping = new Dictionary<string, string>
{
{ "tbVendorName", "Vendor name" },
{ "rtbVendorAddress", "Vendor address" },
{ "tbVendorEmail", "Vendor email" },
{ "tbVendorWebsite", "Vendor Web site" }
};
private readonly IList<string> _requiredFields = new List<string>();
private IList<string> RequiredFields { get { return _brokenRules; } }
private IDictionary<string, string> { get { return _fieldMapping; } }
public bool IsSatisfiedBy(TextBox input)
{
bool valid = true;
// If the condition isn't satisfied, the invalid field's diplay name is
// added to RequiredFields
if(!string.IsNullOrEmpty(input))
{
valid = false;
RequiredFields.Add(FieldMapping[input.Name]);
}
return valid;
}
}
现在,带有验证的事件处理程序将如下所示:
// Instantiating the specification.
ISpecification<TextBox> textBoxSpec = new TextBoxSpecification();
// Now, instead of just checking if it's not null or empty, the .All(...)
// extension method will execute the specification for all text boxes
bool valid = new [] { tbVendorName, rtbVendorAddress, tbVendorEmail, tbVendorWebsite }
.All(textBox => textBoxSpec.IsSatisfiedBy(textBox));
// If all specification were satisfied, you can assign the whole properties
if(valid)
{
VendorName = tbVendorName.Text;
VendorAddress = rtbVendorAddress.Text;
VendorEmail = tbVendorEmail.Text;
VendorWebsite = tbVendorWebsite.Text;
}
else
{
// If not, generates a message box with a comma-separated
// list of required fields!
MessageBox.Show
(
string.Format
(
"The following fields are required: {0}",
textBoxSpec.RequiredFields.ToArray().Join(", ")
)
);
}
在维基百科上了解更多关于规范模式的信息。
private void btnOK_Click(object sender, EventArgs e)
{
var box = Controls.OfType<TextBox>().Any(x => !Validate(x));
if (!box)
{
VendorName = tbVendorName.Text;
VendorAddress = rtbVendorAddress.Text;
VendorEmail = tbVendorEmail.Text;
VendorWebsite = tbVendorWebsite.Text;
}
}
private bool Validate(TextBox box)
{
if (!String.IsNullOrEmpty(box.Text)) return true;
MessageBox.Show(@"vender " + new List<string> {"name","email","website","address"}
.Single(x => box.Name.ToLower().Contains(x)) + @" is required!...");
return false;
}
您可以控制采集并检查其类型,然后应用等验证
foreach(Control c in this.Controls)
{
//Check if it's input control
if(c is TextBox)
{
if (string.IsNullOrEmpty(c.Text))
{
MessageBox.Show("Value Required");
}
}
}
只需使用Required Field验证器和Regular表达式验证器,就可以避免编写大量javascript。只需谷歌required field validator
您可以编写通用函数,该函数使用IsNullOrEmpty验证值,并设置VendorName、VendorWebsite等或显示错误消息。
虽然我更喜欢一种在输入必要字段之前不允许单击"OK"的方法,但如果这只是一个"修饰"代码的请求,即减少嵌套,您可以提前检查条件。
if (string.IsNullOrEmpty(tbVendorName.Text))
{
MessageBox.Show("Vendor name is required");
return;
}
if (string.IsNullOrEmpty(rtbVendorAddress.Text))
{
MessageBox.Show("Vendor address is required");
return;
}
if (string.IsNullOrEmpty(tbVendorEmail.Text))
{
MessageBox.Show("Vendor email is required");
return;
}
if (string.IsNullOrEmpty(tbVendorWebsite.Text))
{
MessageBox.Show("Vendor Website Required");
return;
}
VendorName = tbVendorName.Text;
VendorAddress = rtbVendorAddress.Text;
VendorEmail = tbVendorEmail.Text;
VendorWebsite = tbVendorWebsite.Text;
附带说明一下,您目前只允许空白(也不对格式进行任何验证),因此最好使用String.IsNullOrWhitespace()
你要做的第一件事就是创建一组验证类型,比如一个方法用于所有类型的电子邮件验证,返回类型应该是布尔值。只要您想验证任何电子邮件字段。只需调用方法即可。如果要检查多个字段的有效性。只需使用以下语法即可。
if(Control1IsValid&&Control2IsValid){
}
假设您将TabOrder
应用于(富)文本框,并将错误消息保留在其标记属性中,则可以执行以下操作:
private void btnOk_Click(object sender, EventArgs e)
{
var emptyTb = this.Controls.OfType<TextBox>()
.Cast<Control>()
.Union(this.Controls.OfType<RichTextBox>()
.Cast<Control>())
.OrderBy(tb => tb.TabIndex)
.FirstOrDefault(tb => string.IsNullOrEmpty(tb.Text));
if (emptyTb != null)
{
MessageBox.Show(emptyTb.Tag.ToString());
}
}
注意:性能上有一些成本,但方法的代码更容易阅读和维护