Как получить бесплатную запись в словаре C # - PullRequest
2 голосов
/ 29 июня 2009

Я работаю на сервере, и я хотел бы иметь словарь пользователей и дать каждому пользователю определенное число.

Dictionary<int,ServerSideUser> users = new Dictionary<int,ServerSideUser>();

Ключ представляет пользователя на сервере, поэтому, когда люди отправляют сообщения этому пользователю, они отправляют его на этот номер. Я мог бы также использовать IP-адрес пользователя, но это не очень хорошая идея.

Мне нужно назначить такой номер для каждого пользователя, и я действительно не уверен, как это сделать. Кто-то предложил что-то вроде

Enumerable.Range(int.MinValue, int.MaxValue)
.Except(users.Select(x => x.Key)).First();

но я действительно не думаю, что это оптимальный путь. Кроме того, у меня та же проблема с List (или LinkedList) где-то еще.

Есть идеи?

Ответы [ 9 ]

9 голосов
/ 29 июня 2009

Если размер «числа» не имеет значения, возьмите Guid, он всегда будет уникальным и не угадываемым.

3 голосов
/ 29 июня 2009

Если вам нужен словарь, в котором используется произвольный, упорядоченный целочисленный ключ, вы также можете использовать List<ServerSideUser>, в котором индекс списка служит ключом.

Есть ли конкретная причина, по которой вам нужно использовать Dictionary?

Использование List<> или аналогичной структуры данных определенно имеет ограничения. Из-за проблем с параллелизмом вы вообще не захотите удалять пользователей из списка, кроме случаев, когда сервер отключается. В противном случае может возникнуть сценарий, в котором пользователь 255 отправляет сообщение пользователю 1024, который отключается и заменяется новым пользователем 1024. Затем новый пользователь 1024 получает сообщение, предназначенное для старого пользователя 1024.

Если вы хотите иметь возможность управлять объемом памяти в списке пользователей, многие другие подходы здесь работают; Ответ Уилла особенно хорош, если вы хотите использовать ints вместо Guids.

1 голос
/ 29 июня 2009

Прежде всего, я бы также начал с предложения по GUID. Во-вторых, я предполагаю, что вы каким-то образом сохраняете пользовательскую информацию на сервере, и это, скорее всего, база данных. Если это так, почему бы не позволить базе данных выбрать уникальный идентификатор для каждого пользователя через первичный ключ? Может быть, это не лучший выбор для того, что вы пытаетесь сделать здесь, но это та проблема, с которой базы данных работали годами, поэтому зачем изобретать заново?

1 голос
/ 29 июня 2009

Предлагаю сочетание вашего подхода и пошагового.

Поскольку ваши данные находятся в памяти, достаточно иметь идентификатор типа int. Создайте переменную для следующего пользователя и связанный список свободных идентификаторов.

Когда добавляется новый пользователь, используйте идентификатор из списка. Если список пуст - используйте переменную и увеличивайте ее.

Когда пользователь удаляется, добавьте его идентификатор в словарь.

P.S. Рассмотрите возможность использования базы данных.

1 голос
/ 29 июня 2009

Другой вариант: использовать фабрику для генерации экземпляров ServerSideUser, которая присваивает новый уникальный идентификатор каждому пользователю.

В этом примере фабрика - это сам класс. Вы не можете создать экземпляр класса, вы должны получить новый экземпляр, вызвав статический метод Create для этого типа. Он увеличивает генератор идентификаторов и создает новый экземпляр с этим новым идентификатором. Есть много способов сделать это потокобезопасным способом, я делаю это здесь в элементарной 1.1-совместимой форме (псевдокод c #, который может на самом деле компилироваться):

public class ServerSideUser
{
  // user Id
  public Id {get;private set;}
  // private constructor
  private ServerSideUser(){}
  private ServerSideUser(int id) { Id = id; }

  // lock object for generating an id
  private static object _idgenLock = new Object();
  private static int _currentId = 0; // or whatever
  // retrieves the next id; thread safe 
  private static int CurrentId
  {
    get{ lock(_idgenLock){ _currentId += 1; return _currentId; } }
  }  

  public static ServerSideUser Create()
  {
    return new ServerSideUser(CurrentId);
  }
}
1 голос
/ 29 июня 2009

Почему вы не отслеживаете текущее максимальное число и не увеличиваете его на единицу при каждом добавлении нового пользователя?

0 голосов
/ 30 июня 2009

Может быть, немного брутально, но может ли DateTime.Now.Ticks быть чем-то для вас? В качестве дополнительного бонуса вы знаете, когда пользователь был добавлен в ваш диктант.

Из документов MSDN о тиках ...

Один тик представляет сто наносекунд или одну десятую миллионную часть второй. В миллисекунде 10 000 тиков.

Значение этого свойства представляет количество интервалов в 100 наносекунд. прошедшие с 12:00:00 до полуночи 1 января 0001 г., представляет DateTime .. ::. MinValue.

0 голосов
/ 29 июня 2009

Почему бы просто не начать с 1 и считать вверх?

lock(dict) {
   int newId = dict.Count + 1;
   dict[newId] = new User();
}

Если вы действительно обеспокоены тем, что половина населения мира появляется на вашем одном сервере, попробуйте вместо этого использовать long: s ..: -D

0 голосов
/ 29 июня 2009

Я думаю, это зависит от того, как вы определяете «уникальность» клиентов.

Например, если у вас два разных клиента на одном компьютере, вы считаете их двумя клиентами или одним?

Я рекомендую вам использовать long значение, представляющее время установления соединения, например, "hhmmss", или даже вы можете включить миллисекунды

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...