Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/amazon-s3/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 基本用户输入字符串验证_C#_Validation - Fatal编程技术网

C# 基本用户输入字符串验证

C# 基本用户输入字符串验证,c#,validation,C#,Validation,我在person抽象类的name属性中写了一个检查。我遇到的问题是,我正在尝试实现一段代码,该代码不允许用户将字段留空,也不允许用户使用35个字符超过名称限制,也不允许输入一个数字,但我仍然坚持使用它。如果有人能帮助或建议我 public string Name { get { return name; } set { while (true) {

我在person抽象类的name属性中写了一个检查。我遇到的问题是,我正在尝试实现一段代码,该代码不允许用户将字段留空,也不允许用户使用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;                
        }
    }

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


这种验证应该被打破。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);
    }
}

首先,不要在setter内部请求控制台输入。这是一种非常糟糕的做法。相反,您应该从setter抛出一个异常,并让调用方根据需要处理该异常:

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;
    }
}

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

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

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
}

话虽如此,我相信你会从其他答案中看到,改变名字的位置。一般来说,访问器只用于快速“获取”和“设置”类中的内容。

不要在属性中执行任何形式的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;
    }
}
确切的正则表达式有待讨论,但最佳实践是:

  • 不要试图列出并拒绝所有你不喜欢的模式。太多的可能性
  • 接受你的期望(和理解),拒绝其他一切
我将创建一个方法来更改包含验证逻辑的名称。如果您想检查名称是否有效,因此不必处理argumentexception,请先进行检查,在调用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);

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

祝你好运

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;

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

这让我想起了我以前编写的一段代码,其中setter正在打开一个套接字并通过网络发送内容! 代码应该执行它所读取的操作,想象一下,如果有人使用了您的代码,调用了您的setter,并想知道他/她的应用程序到底为什么会挂起(等待用户输入)

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


关于,

我没有时间给出完整的答案,但就试图编写惯用C#代码而言,让setter提示用户输入是一个非常糟糕的主意…@JonSkeet很抱歉这个天真的问题,但什么是惯用C#代码?将用户困在字段中是糟糕的UI设计。@JamesAlexander惯用代码[在任何语言中]是遵循普遍或广泛接受的使用模式的代码。它的代码“看起来”像该语言中的其他代码。在属性设置器中执行控制台Iteraction不是C#中常见的操作。这不仅不是一个习惯用语,也不是一个好主意的时期。要明确的是,这不仅仅是因为它是一个属性设定者,这是一个坏主意。您的Person类不应该执行IO期间!将此更改为方法不会使设计变得更好。IO应该由一个专门的类(比如你的程序类或更好的类)来处理——你在这里违反的原则叫做关注点分离:。他需要做相反的事情;这应该是一个
continue
,就像前面的
break
实例一样。但这根本不应该存在。许多noob程序员对他们设计有缺陷的代码中的语法/逻辑错误提出疑问。我的答案是帮助他解决他的bug(这是他问题的答案),而不是重新设计他的代码(虽然这会更有帮助),对此投反对票是愚蠢的。@Shreder-同意投反对票,但值得花时间指出真正令人震惊的问题。@RitchMelton我试图通过说“除了Skeet说的话”来指出这一点,既然已经提到了,我想我应该重申一下more@Shredder:我没有投反对票;我指出的问题是与您的逻辑相反(并且已经纠正了),您知道属性在很大程度上只是getter/setter方法的语法糖。在setter之外处理验证是一个好主意,但是没有必要完全离开属性。我知道,但是我仅仅看到一个属性列表并不能告诉您可以在模型上执行什么(假设Person是某种域模型),而是看到一堆动词(方法)另外,我通常不希望属性在设置其值时抛出异常我修改了您的代码,因为我的visual studio不理解regex部分
var yourClassInstance = new YourClass();

string input
bool inputRead = false;

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

    inputRead = YourClass.IsNameValid(input);
}

yourClassInstance.Name = inputRead;