Каков наилучший способ использования пары (тройной и т. Д.) Значений в качестве одного значения в C #? - PullRequest
20 голосов
/ 19 сентября 2008

То есть я хотел бы иметь кортеж значений.

Случай использования на мой взгляд:

Dictionary<Pair<string, int>, object>

или

Dictionary<Triple<string, int, int>, object>

Существуют ли встроенные типы, такие как Pair или Triple? Или как лучше это реализовать?

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

Обновление 2 Полагаю, стоит напомнить, что когда вы используете какое-либо значение в качестве ключа в словаре, оно должно быть неизменным.

Ответы [ 16 ]

20 голосов
/ 19 сентября 2008

Встроенные классы

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

Пары и тройки

универсальный System.Collections.Generic.KeyValuePair класс может быть использован как реализация пары adhoc. Это класс, который Общий словарь использует внутренне.

Кроме того, вы можете обойтись System.Collections.DictionaryEntry структура, которая действует как элементарная пара и имеет преимущество быть доступным в Mscorlib. С другой стороны, это то, что эта структура не строго типизированный.

Пары и тройки также доступны в виде System.Web.UI.Pair и System.Web.UI.Triplet классы. Несмотря на то, что эти классы находятся в сборке System.Web они могли бы быть идеально подходящими для разработки формы win. Тем не менее, эти классы также не является строго типизированным и может не подходить для некоторых сценариев, таких как универсальная структура или библиотека.

Кортежи высшего порядка

Для кортежей более высокого порядка, если не считать собственного класса, может не будет простым решением.

Если вы установили F # язык , вы можете сослаться на FSharp.Core.dll , который содержит набор универсальных неизменяемых Microsoft.Fsharp.Core.Tuple классы до общего числа. Тем не менее, даже при неизменном FSharp.Code.dll может быть распространен, F # является исследовательским языком и незавершенным Это решение может быть интересным только в академических кругах.

Если вы не хотите создавать свой собственный класс и вам неудобно ссылаясь на библиотеку F #, один изящный трюк может заключаться в расширении универсального класса KeyValuePair, чтобы член Value сам был вложенным KeyValuePair.

Например, следующий код иллюстрирует, как вы можете использовать KeyValuePair для создания троек:

int id = 33;
string description = "This is a custom solution";
DateTime created = DateTime.Now;

KeyValuePair<int, KeyValuePair<string, DateTime>> triple =
   new KeyValuePair<int, KeyValuePair<string, DateTime>>();
triple.Key = id;
triple.Value.Key = description;
triple.Value.Value = created;

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

KeyValuePair<KeyValuePair<KeyValuePair<string, string>, string>, string> quadruple =
    new KeyValuePair<KeyValuePair<KeyValuePair<string, string>, string>, string>();
KeyValuePair<KeyValuePair<KeyValuePair<KeyValuePair<string, string>, string>, string>, string> quintuple =
    new KeyValuePair<KeyValuePair<KeyValuePair<KeyValuePair<string, string>, string>, string>, string>();

Roll Your Own

В других случаях вам, возможно, придется прибегнуть к класс кортежа, и это не сложно.

Вы можете создавать простые структуры, например:

struct Pair<T, R>
{
    private T first_;
    private R second_;

    public T First
    {
        get { return first_; }
        set { first_ = value; }
    }

    public R Second
    {
        get { return second_; }
        set { second_ = value; }
    }
}

Каркасы и библиотеки

Эта проблема уже решалась ранее и фреймворки общего назначения. существуют Ниже приведена ссылка на один из таких фреймворков:

12 голосов
/ 19 сентября 2008
public struct Pair<T1, T2>
{
    public T1 First;
    public T2 Second;
}

public struct Triple<T1, T2, T3>
{
    public T1 First;
    public T2 Second;
    public T3 Third;
}
11 голосов
/ 15 августа 2010

Перемотка вперед до 2010, .NET 4.0 теперь поддерживает n-кортежей произвольных n . Эти кортежи реализуют структурное равенство и сравнение, как и ожидалось.

9 голосов
/ 19 сентября 2008

Pair и Triplet - это существующие классы в .net, см. Msdn:

Триплет

пара

Я недавно сталкивался с ними, играя с декодированием состояния вида

6 голосов
/ 19 сентября 2008

Я реализовал библиотеку кортежей в C #. Зайдите на страницу http://www.adventuresinsoftware.com/generics/ и нажмите ссылку "кортежи".

3 голосов
/ 19 сентября 2008

Я обычно просто создаю свою собственную структуру, содержащую значения. Это часто немного более читабельно;)

2 голосов
/ 01 апреля 2010

Одно простое решение еще не было упомянуто. Вы также можете просто использовать List<T>. Он встроен, эффективен и прост в использовании. Конечно, поначалу это выглядит немного странно, но отлично справляется со своей задачей, особенно для большого количества элементов.

2 голосов
/ 19 сентября 2008

Вы можете относительно легко создавать свои собственные классы кортежей, единственное, что потенциально может привести к путанице, - это равенство и переопределение хеш-кода (важно, если вы собираетесь использовать их в словарях).

Следует отметить, что собственная KeyValuePair<TKey,TValue> структура .Net имеет относительно медленное равенство и методы хеширования .

Предполагая, что вас это не беспокоит, проблема в том, что код в конце концов трудно определить:

public Tuple<int, string, int> GetSomething() 
{
    //do stuff to get your multi-value return
}

//then call it:
var retVal = GetSomething();

//problem is what does this mean?
retVal.Item1 / retVal.Item3; 
//what are item 1 and 3?

В большинстве этих случаев мне проще создать определенный класс записей (по крайней мере, пока C # 4 не сделает это волшебством компилятора)

class CustomRetVal {
    int CurrentIndex { get; set; }
    string Message { get; set; }
    int CurrentTotal { get; set; }
}

var retVal = GetSomething();

//get % progress
retVal.CurrentIndex / retVal.CurrentTotal;
2 голосов
/ 19 сентября 2008

KeyValuePair - лучший класс для расширения, если вы не хотите создавать свои собственные классы.

int id = 33;
string description = "This is a custom solution";
DateTime created = DateTime.Now;

KeyValuePair<int, KeyValuePair<string, DateTime>> triple =
   new KeyValuePair<int, KeyValuePair<string, DateTime>>();
triple.Key = id;
triple.Value.Key = description;
triple.Value.Value = created;

Вы можете расширить его на любое количество уровней.

KeyValuePair<KeyValuePair<KeyValuePair<string, string>, string, string> quadruple =
   new KeyValuePair<KeyValuePair<KeyValuePair<string, string>, string, string>();

Примечание : классы Triplet и Pair существуют внутри System.Web -dll, поэтому они не очень подходят для других решения, чем ASP.NET.

1 голос
/ 02 ноября 2009

NGenerics - популярная библиотека .Net алгоритмов и структур данных, недавно представила неизменные структуры данных для набора

Первыми неизменными были реализованы классы pair и tuple . Код хорошо покрыт тестами и довольно элегантен. Вы можете проверить это здесь . В настоящее время они работают над другими неизменными альтернативами, и они должны быть готовы в ближайшее время.

...