我目前正在开发一个聊天服务器作为学校项目。 我在服务器上有一些名称条件,所以我创建了一个调用方法来强制执行这些规则。 任何时候都不接受名字。该方法将再次称之为自我。 除此之外,该方法应该防止人们使用相同的名称。
我启动服务器,telnet到client1。然后我将client1的名称设置为:bob
然后我telnet到client2的服务器。如果我尝试将名称设置为bob,则会被拒绝 - 因为它应该是。 如果我然后将名称设置为bobby,则接受。方法完成,名称已设置。
现在出现了奇怪的部分。将名称设置为可用的有效名称后,名称将再次更改。到我试过的第一个(不可用)名字(bob)。
所以我尝试了一些断点,认为我在对该方法的递归调用中犯了一个错误。但是在名称更改为bob的passthrough中,它不会激活我放在阅读器上的断点,或者应该阻止将名称设置为不可用名称的检查。
我的代码:
class NameHandler
{
private readonly List<string> AllNames = new List<string>();
public void SetName(StreamWriter writer, Client client)
{
var reader = new StreamReader(new NetworkStream(client.GetSocket));
var name = reader.ReadLine();
if(!IsNameAvailable(name))
{
writer.WriteLine("That name is in use. Pick an other one");
SetName(writer, client);
}
try
{
client.Name = name;
}
catch(ArgumentOutOfRangeException)
{
writer.WriteLine("Max length of name is 10.");
writer.WriteLine("Try again please:");
SetName(writer, client);
}
catch(ArgumentNullException)
{
writer.WriteLine("Invalid name");
writer.WriteLine("Try again please:");
SetName(writer, client);
}
catch (ArgumentException)
{
writer.WriteLine("The name may not contain spaces");
writer.WriteLine("Try again please:");
SetName(writer, client);
}
AllNames.Add(client.Name.ToLower());
writer.WriteLine("Your name was successfully updated.");
}
private bool IsNameAvailable(string name)
{
return !AllNames.Contains(name.ToLower());
}
}
Client类,包含在实例化时传递给它的唯一套接字。 每个客户端都有自己唯一的本地端口。这已经多次验证过。
答案 0 :(得分:3)
问题是SetName
成功完成bobby
后,它会返回到调用它的位置,即此处:
if(!IsNameAvailable(name))
{
writer.WriteLine("That name is in use. Pick an other one");
SetName(writer, client); //Control returns to here
}
本地name
变量仍设置为bob
,然后执行下一个代码块:
try
{
client.Name = name;
}
将Name
属性设置为您已发现不可用的属性。简单的解决方法是在您再次递归调用SetName
后立即退出函数:
if(!IsNameAvailable(name))
{
writer.WriteLine("That name is in use. Pick an other one");
SetName(writer, client);
return;
}
这样当控制返回到外部函数时,它将立即返回,并且不再尝试更改名称。您可能需要在异常处理程序中的每个调用之后立即返回。
答案 1 :(得分:1)
我认为你错过了其他部分。在递归调用的函数返回后,即使名称“不可用”,也始终执行赋值client.Name = name;
。我认为这不是故意的。