遍历列表元组并在没有匹配项时添加
Loop through list tuples and add if there is no match
我正在用 C# 编写一个游戏服务器,每次有人用他的用户名发送登录消息时,我都会将他添加到 ID、IPENDPOINT、USERNAME 的元组列表中。
我想检查客户端是否与已连接的客户端没有相同的用户名,所以我尝试遍历列表并获取 list.Item3 'which is username' 并使用 String.Equals(list.Item3, username ) 检查用户名是否存在。
我的问题是当我循环时,我的代码只与列表中的第一个元组进行比较,如果它是真的则发送一条错误消息,如果不是则发送接受消息并且当列表有 +1 客户端时它也只与第一个比较并接受即使元组编号 2 或 3... 具有该用户名。
我尝试了很多方法,这是我最后尝试的代码:
for (int i = 0; i < clientsInfoList.Count; i++)
{
bool isUsed;
if (String.Equals(clientsInfoList[i].Item3, Username))
{
isUsed = true;
}
if (isUsed)
{
Console.WriteLine("Username is already used!");
udpServer.Send(Encoding.ASCII.GetBytes("REFUSED"), Encoding.ASCII.GetByteCount("REFUSED"), remoteEP);
break;
}
else if(!isUsed)
{
clientsInfoList.Add(new Tuple<int, IPEndPoint, string>(id, remoteEP, Username));
Console.WriteLine("Username has been added to the list :)");
udpServer.Send(Encoding.ASCII.GetBytes("ACCEPTED"), Encoding.ASCII.GetByteCount("ACCEPTED"), remoteEP);
}
}
我试了很多其他方法都无法验证。
提前致谢。
为什么要将整个逻辑放在 for 循环中?仅将以下代码放在 for 循环中。
bool isUsed;
if (String.Equals(clientsInfoList[i].Item3, Username))
{
isUsed = true;
}
它现在将验证元组中的所有元素并执行剩余的逻辑。
你把一切都放在一个循环中。为什么?您应该只使用循环来检查用户名是否被使用,并将您的消息发送到它之外。
首先你想强制你的循环只在它应该工作的时候工作。您可以通过在它之前声明 isUsed
并将其添加到条件中来实现。然后,在循环中,您只检查名称是否被占用并更改变量的值。循环将遍历所有客户端或在遇到符合条件的名字时结束。当循环结束后,你应该根据结果来决定发送哪个命令。
bool isUsed = false;
for (int i = 0; i < clientsInfoList.Count && !isUsed; i++)
{
isUsed = String.Equals(clientsInfoList[i].Item3, Username);
}
if (isUsed)
{
Console.WriteLine("Username is already used!");
udpServer.Send(Encoding.ASCII.GetBytes("REFUSED"), Encoding.ASCII.GetByteCount("REFUSED"), remoteEP);
}
else
{
clientsInfoList.Add(new Tuple<int, IPEndPoint, string>(id, remoteEP, Username));
Console.WriteLine("Username has been added to the list :)");
udpServer.Send(Encoding.ASCII.GetBytes("ACCEPTED"), Encoding.ASCII.GetByteCount("ACCEPTED"), remoteEP);
}
你完全以错误的方式解决这个问题,如果我是你,我会做的第一件事就是摆脱元组,创建一个 class 其中包含你需要的 3 个属性.
此外,在这种情况下,请尝试使用 HashSet 而不是列表,它们会得到更好的优化,如果您有大量客户,它们将帮助您的游戏 运行 更快。
实现您所要求的最简洁的方法是使用 LINQ,这是我重写您上面编写的代码的方法。
public class Game
{
public Game()
{
this.Clients = new HashSet<Clients>();
}
public HashSet<Client> Clients { get; set;}
public void OnClientConnect(Client newClient)
{
// Are there any clients with the username that the newUser is attempting to use?
bool usernameIsFree = this.Clients.Any(clients => clients.UserName == newClient.UserName);
if (usernameIsFree)
{
this.Clients.Add(newClient);
Console.WriteLine("Username has been added to the list :)");
// UDP stuff here...
return;
}
Console.WriteLine("Username is already used!");
// UDP stuff here
}
}
public class Client
{
public int ClientId { get; set; }
public IPEndPoint IPEndPoint { get; set; }
public string UserName { get; set; }
}
你可以做到
var isUsed = clientsInfoList.Any(info => info.Item3 == Username);
if (isUsed)
{
// ...
}
else
{
// ...
}
我假设 Item3
(Tuple<T1, T2, T3>
的 T3
)和 Username
都具有 编译时间 类型 string
.
我正在用 C# 编写一个游戏服务器,每次有人用他的用户名发送登录消息时,我都会将他添加到 ID、IPENDPOINT、USERNAME 的元组列表中。 我想检查客户端是否与已连接的客户端没有相同的用户名,所以我尝试遍历列表并获取 list.Item3 'which is username' 并使用 String.Equals(list.Item3, username ) 检查用户名是否存在。 我的问题是当我循环时,我的代码只与列表中的第一个元组进行比较,如果它是真的则发送一条错误消息,如果不是则发送接受消息并且当列表有 +1 客户端时它也只与第一个比较并接受即使元组编号 2 或 3... 具有该用户名。 我尝试了很多方法,这是我最后尝试的代码:
for (int i = 0; i < clientsInfoList.Count; i++)
{
bool isUsed;
if (String.Equals(clientsInfoList[i].Item3, Username))
{
isUsed = true;
}
if (isUsed)
{
Console.WriteLine("Username is already used!");
udpServer.Send(Encoding.ASCII.GetBytes("REFUSED"), Encoding.ASCII.GetByteCount("REFUSED"), remoteEP);
break;
}
else if(!isUsed)
{
clientsInfoList.Add(new Tuple<int, IPEndPoint, string>(id, remoteEP, Username));
Console.WriteLine("Username has been added to the list :)");
udpServer.Send(Encoding.ASCII.GetBytes("ACCEPTED"), Encoding.ASCII.GetByteCount("ACCEPTED"), remoteEP);
}
}
我试了很多其他方法都无法验证。 提前致谢。
为什么要将整个逻辑放在 for 循环中?仅将以下代码放在 for 循环中。
bool isUsed;
if (String.Equals(clientsInfoList[i].Item3, Username))
{
isUsed = true;
}
它现在将验证元组中的所有元素并执行剩余的逻辑。
你把一切都放在一个循环中。为什么?您应该只使用循环来检查用户名是否被使用,并将您的消息发送到它之外。
首先你想强制你的循环只在它应该工作的时候工作。您可以通过在它之前声明 isUsed
并将其添加到条件中来实现。然后,在循环中,您只检查名称是否被占用并更改变量的值。循环将遍历所有客户端或在遇到符合条件的名字时结束。当循环结束后,你应该根据结果来决定发送哪个命令。
bool isUsed = false;
for (int i = 0; i < clientsInfoList.Count && !isUsed; i++)
{
isUsed = String.Equals(clientsInfoList[i].Item3, Username);
}
if (isUsed)
{
Console.WriteLine("Username is already used!");
udpServer.Send(Encoding.ASCII.GetBytes("REFUSED"), Encoding.ASCII.GetByteCount("REFUSED"), remoteEP);
}
else
{
clientsInfoList.Add(new Tuple<int, IPEndPoint, string>(id, remoteEP, Username));
Console.WriteLine("Username has been added to the list :)");
udpServer.Send(Encoding.ASCII.GetBytes("ACCEPTED"), Encoding.ASCII.GetByteCount("ACCEPTED"), remoteEP);
}
你完全以错误的方式解决这个问题,如果我是你,我会做的第一件事就是摆脱元组,创建一个 class 其中包含你需要的 3 个属性.
此外,在这种情况下,请尝试使用 HashSet 而不是列表,它们会得到更好的优化,如果您有大量客户,它们将帮助您的游戏 运行 更快。
实现您所要求的最简洁的方法是使用 LINQ,这是我重写您上面编写的代码的方法。
public class Game
{
public Game()
{
this.Clients = new HashSet<Clients>();
}
public HashSet<Client> Clients { get; set;}
public void OnClientConnect(Client newClient)
{
// Are there any clients with the username that the newUser is attempting to use?
bool usernameIsFree = this.Clients.Any(clients => clients.UserName == newClient.UserName);
if (usernameIsFree)
{
this.Clients.Add(newClient);
Console.WriteLine("Username has been added to the list :)");
// UDP stuff here...
return;
}
Console.WriteLine("Username is already used!");
// UDP stuff here
}
}
public class Client
{
public int ClientId { get; set; }
public IPEndPoint IPEndPoint { get; set; }
public string UserName { get; set; }
}
你可以做到
var isUsed = clientsInfoList.Any(info => info.Item3 == Username);
if (isUsed)
{
// ...
}
else
{
// ...
}
我假设 Item3
(Tuple<T1, T2, T3>
的 T3
)和 Username
都具有 编译时间 类型 string
.