#c# #.net #generics #dictionary
#c# #.net #общие сведения #словарь
Вопрос:
Мне нужно создать что-то вроде словаря, где ключом была бы пара enum и int, а значением — object. Итак, я хочу сопоставить пару с некоторым объектом.
Одним из вариантов было бы
public enum SomeEnum
{
value1, value2
}
class Key
{
public SomeEnum;
public int counter;
// Do I have to implement Compare here?
}
Dictionary<SomeEnum, object> _myDictionary;
Другим вариантом было бы преобразовать enum и int в некоторый уникальный ключ.
string key = String.Format("{0}/{1}", enumValue, intValue)
Такой подход требует синтаксического анализа строк, много дополнительной работы.
Как сделать это легко?
Комментарии:
1. Какую версию C # вы используете?
2. Visual Studio 2008, поэтому я думаю, что это 3.5
Ответ №1:
Я бы выбрал что-то похожее на
public enum SomeEnum
{
value1, value2
}
public struct Key
{
public SomeEnum;
public int counter;
}
Dictionary<Key, object>
Я думаю, что это помогло бы?
Комментарии:
1. Да, это, безусловно, самое простое 🙂
2. Как два ключа будут сравниваться по словарю? Использует ли он == или IComparable?
3. Это тип значения, поэтому он просто выполнит == . Я не уверен насчет 32-разрядных систем, но в 64-разрядной системе, я думаю, было бы просто сравнить две ячейки памяти, поскольку перечисление и int поместятся в 64-разрядную версию, это дешевая операция. На 32-разрядной версии, вероятно, (?) потребовалось бы еще несколько инструкций?
4. Преимуществом этого решения является производительность и простота. Это дешево для сравнения. Но вы не можете управлять сортировкой, например
5. Хм, когда я думаю об этом, вы можете указать порядок, в котором поля хранятся внутри. Это должно позволить вам определить внутреннюю релевантность между перечислением и int
Ответ №2:
Если вы собираетесь поместить это в словарь, то вам нужно будет убедиться, что вы реализуете значимый .Equals
и .GetHashCode
, иначе словарь будет вести себя некорректно.
Я бы начал с чего-то подобного следующему для базового составного ключа, а затем внедрил пользовательский IComparer для получения нужного вам порядка сортировки.
public class MyKey
{
private readonly SomeEnum enumeration;
private readonly int number;
public MyKey(SomeEnum enumeration, int number)
{
this.enumeration = enumeration;
this.number = number;
}
public int Number
{
get { return number; }
}
public SomeEnum Enumeration
{
get { return enumeration; }
}
public override int GetHashCode()
{
int hash = 23 * 37 this.enumeration.GetHashCode();
hash = hash * 37 this.number.GetHashCode();
return hash;
}
public override bool Equals(object obj)
{
var supplied = obj as MyKey;
if (supplied == null)
{
return false;
}
if (supplied.enumeration != this.enumeration)
{
return false;
}
if (supplied.number != this.number)
{
return false;
}
return true;
}
}
Комментарии:
1. 1 за упоминание . Equals и GetHashCode попались. Это хорошая причина использовать тип Tuple вместо того, чтобы использовать свой собственный простой ключ.
2. Я полагаю, что структуры имеют переопределения GetHashCode и Equals по умолчанию, которые дадут правильные результаты, хотя GetHashCode по умолчанию просто хэширует первый элемент в структуре. Производительность будет хорошей, если большинство структур отличаются первым элементом, и очень плохой, если большинство структур имеют один и тот же первый элемент.
Ответ №3:
Если вы используете C # 4.0, вы могли бы использовать класс Tuple.
var key = Tuple.Create(SomeEnum.Value1, 3);
Комментарии:
1. Да, но тогда он неправильно напечатан — т. Е. там нет описания того, из чего состоит ключ. Но да, это возможно
2. Он строго типизирован — ключ имеет тип
Tuple<SomeEnum, int>
.3. Итак, ваш словарь может быть определен как
Dictionary<Tuple<SomeEnum, int>, object>
4. Да, он строго типизирован, но не является описательным. Если вы позже заполучите этот ключ, знаете ли вы, что это за целое число на самом деле? Это моя точка зрения. Это может быть, а может и не быть проблемой. Это зависит 🙂
5. Он «строго типизирован», но не «красиво типизирован». С помощью структуры (или анонимного типа) вы можете получить доступ к элементам с помощью x.nameyousspecify. С помощью кортежа вы получаете доступ к x.Item1, который далеко не так информативен.