Как лучше всего использовать пару (тройку и т. д.) Значений как одно значение в C#?

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

Вариант использования на мой взгляд:

Dictionary<Pair<string, int>, object>

или же

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

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

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

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

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
20
0
13 002
16
Перейти к ответу Данный вопрос помечен как решенный

Ответы 16

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

Встроенных модулей нет, но создать класс Pair <T, R> несложно.

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

Триплет

Пара

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

1. Они находятся в Web.UI :-) 2. Они не являются общими 3. А как насчет GetHashCode?

Max Galkin 19.09.2008 17:48

Я большой поклонник Triplet при динамическом добавлении элементов управления на веб-страницу.

David Basarab 19.09.2008 18:01

1, Да, они есть, как я уже сказал, я видел, что это используется на сайте asp.net, поэтому я подумал, что упомяну об этом. 2, это снова правда, если вам нужно что-то общее, я бы пошел с решением yshuditelu 3, что насчет этого?

Adam Vigh 19.09.2008 19:07

3. Если они не отменяют GetHashCode () и Equals (), вы не можете использовать их для ключей в коллекциях. См. Ссылку в вопросе.

Max Galkin 19.09.2008 22:45

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;
}

Да, есть System.Web.UI.Pair и System.Web.UI.Triplet (у которого есть перегруженный создатель для поведения типа Pair!)

В первом случае я обычно использую

Dictionary<KeyValuePair<string, int>, object>

Для этого нет встроенных классов. Вы можете использовать KeyValuePair или развернуть свою собственную реализацию.

Вы можете использовать System.Collections.Generic.KeyValuePair в качестве реализации Pair.

Или вы можете просто реализовать свои собственные, это не сложно:

public class Triple<T, U, V>
{
  public T First {get;set;}
  public U Second {get;set;}
  public V Third {get;set;}
}

Конечно, когда-нибудь вы можете столкнуться с проблемой, что Triple (string, int, int) несовместим с Triple (int, int, string). Возможно, вместо этого используйте System.Xml.Linq.XElement.

Эта реализация неверна. См. Ссылку в вопросе. Если вы используете класс для кортежа, вы не можете использовать его в качестве ключа в словаре, потому что, если вы не переопределите GetHashCode ()

Max Galkin 18.06.2009 00:38
Ответ принят как подходящий

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

Да, вроде бы неплохая реализация. Не могли бы вы разместить здесь свой код для класса Tuple? Мне также кажется, что в вашей функции GetHashCode () есть возможность переполнения, не так ли?

Max Galkin 18.06.2009 00:42

А еще мне нравится класс "Sextuple" ;-)

Max Galkin 18.06.2009 00:43

Извините, у меня недостаточно символов, чтобы разместить здесь код. Я должен поставить «не отмечен» на метод GetHashCode. Хороший улов.

Michael L Perry 18.06.2009 02:37

Ну, может быть, несколько сокращенная версия, чтобы дать быстрый пример? .. Эээ, без ToString () ... Что касается GetHashCode (), я хотел бы использовать модуль calc (%), но тогда ваша идея кажется лучше: нам просто нужно "some" int как можно быстрее.

Max Galkin 18.06.2009 11:35

В F# также есть типы Tuple <>; вам просто нужно сослаться на FSharp.Core.dll.

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>();

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

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

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

Пары и тройки

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

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

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

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

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

Если вы установили 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>();

Сверните свой собственный

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

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

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; }
    }
}

Фреймворки и библиотеки

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

Отличное резюме всех доступных методов.

Ron Warholic 02.11.2009 19:56

Библиотека .NET 4.0, которая в настоящее время находится в стадии бета-тестирования, также включает кортежи.

Ian G 02.11.2009 20:32

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

Следует отметить, что собственная структура 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;

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

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

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

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

Другие вопросы по теме