基本的用户输入字符串验证

时间:2011-09-28 17:23:57

标签: c# validation

我一直在我的人抽象类的名字属性中写一张支票。我的问题是,我试图实现一段代码,不允许用户将字段留空或超过35个字符的名称限制或输入数字,但我坚持使用它。如果有人可以帮助或建议我。

    public string Name
    {
        get { return name; }

        set 
        {
            while (true)
            {
                if (value == "" || value.Length > 35)
                {
                    Console.Write("Please Enter Correct Name: ");
                    value = Console.ReadLine();
                    continue;
                }

                foreach (char item in value)
                {                        
                    if (char.IsDigit(item))
                    {
                        Console.Write("Digits Are NotAllowed....\n");
                        Console.Write("Please Enter Correct Name: ");
                        value = Console.ReadLine();
                        break;
                    }
                }
                break;
            }
            name = value;                
        }
    }

9 个答案:

答案 0 :(得分:20)

不要在属性中执行任何形式的UI或I / O.

public string Name
{
    get { return _name; }

    set 
    {
        if (! Regex.IsMatch(value, @"\w{1-35}"))
           throw new ArgumentException("Name must be 1-35 alfanum");
        _name = value;
    }
}

准确的正则表达式可供讨论,但最佳做法是:

  • 不要尝试列出并拒绝您不喜欢的所有模式。太多的可能性。
  • 接受你的期望(和理解),拒绝其他一切。

答案 1 :(得分:6)

应该打破这种验证。 setter应该只知道它具有的各种限制,并且在无效值使得它远远的情况下抛出异常。 不要将用户界面代码放在那里

尝试这样的事情:

public string Name
{
    get { return name; }

    set 
    {
        if (value == "" || value.Length > 35)
        {
            throw new ArgumentException("Invalid name length.");
        }

        foreach (char item in value)
        {                        
            if (char.IsDigit(item))
            {
                throw new ArgumentException("Digits are not allowed.");
            }
        }

        name = value;                
    }
}

然后在您的控制台应用程序中出现类似的内容:

bool success = false;

while(!success)
{
    try
    {
        Console.WriteLine("Please enter a name:");
        myObject.Name = Console.ReadLine();
        success = true;
    }
    catch(ArgumentException ex)
    {
        Console.WriteLine(ex.Message);
    }
}

答案 2 :(得分:3)

首先,永远不要在setter中请求Console输入。这是认真的坏习惯。相反,你应该从setter中抛出一个Exception,让调用者处理它们所需要的东西:

public string Name
{
    get { return name; }
    set
    {
        if(String.IsNullOrWhiteSpace(value))
            throw new ArgumentException("Name must have a value");
        if(value.Length > 35)
            throw new ArgumentException("Name cannot be longer than 35 characters");
        if(value.Any(c => char.IsDigit(c))
            throw new ArgumentException("Name cannot contain numbers");

        name = value;
    }
}

然后,您可以在调用代码中适当地捕获和处理异常(在您的情况下,将涉及重新提示用户输入)。

答案 3 :(得分:2)

根据你的规则处理这个问题的解决方案几乎是显而易见的,但问题是,最好不要将检查和验证逻辑放在属性的setter方法中,你可以有一个单独的类,例如您的验证责任,您可以告诉它这样做,然后适当地使用结果。在这种情况下,您遵循“告诉,不要问”规则以及“单一责任原则”

祝你好运

答案 4 :(得分:2)

public string Name
{
    get { return name; }
    set { name = value; }
}

public static bool IsNameValid(string name) 
{
    if (string.IsNullOrEmpty(name) || name.Length > 35)
    {
        return false;
    }

    foreach (char item in value)
    {                        
        if (!char.IsLetter(item))
        {
            return false;
        }
    }

    return true;

}

最后是用于读取用户输入的代码段。

var yourClassInstance = new YourClass();

string input
bool inputRead = false;

while(!inputRead) 
{
    var input = Console.ReadLine();

    inputRead = YourClass.IsNameValid(input);
}

yourClassInstance.Name = inputRead;

答案 5 :(得分:1)

对此的简短回答是在值无效时循环:

public string GetName()
{
    String name = String.Null;
    do
    {
        Console.Write("Please Enter Correct Name: ");
        name = Console.ReadLine();
    } while (!ValidateName(name))
}

public bool ValidateName(string name)
{
    //String validation routine
}

话虽如此,我相信你会从其他答案中看到,改变姓名的位置。作为一般规则,访问者实际上只是为了“快速”“获取”和“设置”类中的内容。

答案 6 :(得分:1)

我会创建一个方法来更改包含验证逻辑的名称。如果要检查名称是否有效,那么您不必处理争论,请先进行检查,在调用ChangeName之前调用IsValidName

public class Person
{
    public void ChangeName(string name)
    {
       if (!IsValidName(name))
       {
           throw new ArgumentException(....);
       }
       else
          this.Name = value;
    }

    public bool IsValidName(string name)
    {
        // is the name valid using
    }

    public string Name { get; private set; }
 }

并使用它

 var newName = Console.ReadLine();
 var person = new Person();
 while (!person.IsValidName(newName))
 {
     newName = Console.ReadLine();
 }
 person.ChangeName(newName);

答案 7 :(得分:1)

从语义的角度来看,setter就像它的名字所说的那样,是一个二传手!它应该用于设置类的私有/受保护字段 从可测试性的角度来看,您的设计很难自动测试,更不用说不可能!

这让我想起了一段时间我曾经工作的一些代码,其中一个setter打开一个套接字并通过网络发送东西! 代码应该执行它所读取的内容,想象一下如果有人使用您的代码,调用您的setter并想知道为什么他/她的应用程序挂起(等待用户输入)

我认为代码更具可读性和可测试性的方法是使用一个verifer类来确保用户以正确的格式输入正确的数据。验证者应该将输入流作为数据源,这将有助于您轻松测试它。

此致

答案 8 :(得分:0)

除了Skeet先生所说的,似乎你应该用break替换continue以验证新值(就像你在第一次长度检查中所做的那样):

    if (char.IsDigit(item))
    {
         Console.Write("Digits Are NotAllowed....\n");
         Console.Write("Please Enter Correct Name: ");
         value = Console.ReadLine();
         continue;   //here
     }