递归调用方法会忽略检查并跳过断点

时间:2015-09-18 09:34:54

标签: c# sockets streamreader

我目前正在开发一个聊天服务器作为学校项目。 我在服务器上有一些名称条件,所以我创建了一个调用方法来强制执行这些规则。 任何时候都不接受名字。该方法将再次称之为自我。 除此之外,该方法应该防止人们使用相同的名称。

我启动服务器,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类,包含在实例化时传递给它的唯一套接字。 每个客户端都有自己唯一的本地端口。这已经多次验证过。

2 个答案:

答案 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;。我认为这不是故意的。