我一直在我的人抽象类的名字属性中写一张支票。我的问题是,我试图实现一段代码,不允许用户将字段留空或超过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;
}
}
答案 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
}