Эквиваленты кортежей C # 3.0 (для бедных мужчин)

StackOverflow https://stackoverflow.com/questions/1822687

  •  10-07-2019
  •  | 
  •  

Вопрос

В C # 3.0 я время от времени нахожусь в поисках способов имитировать понятие кортежа. Со временем у меня появились различные «бедняки» реализации, вот несколько из них:

Массив базовых объектов :

object[] poorTuple = new object[]{foo,bar,baz}; // basic object array

Более типизированный , HoHoHo ...

KeyValuePair<TypeA, KeyValuePair<TypeB, TypeC>> poorTuple;

Реализация класса , который может использовать вывод типов (взято из функционального программирования для Реальный мир )

public static class Tuple{
  public static Tuple<T1, T2> Create<T1 foo, T2 bar>{
    return new Tuple<T1, T2>(foo, bar);
  }
}
// later: 
var data = Tuple.Create("foo", 42);

Вопросы:

<Ол>
  • Любые другие способы создать кортеж для бедного человека в C # 3.0 (или языке выбора, в котором отсутствует структура данных).

  • Каков лучший способ получить кортеж в C # 3.0 - если у кого-то есть рекомендации по библиотеке, это приветствуется.

  • В какой момент (да, обобщите для меня) имеет смысл создавать определенный тип, а не что-то вроде списка или кортежа? (ищет практические правила)

  • Это было полезно?

    Решение

    Вы можете создавать анонимные типы, которые функционируют аналогично кортежам, кроме как с полезными именами:

    var itemsWithChildCounts 
        = myObjects.Select(x => new { Name = x.Name, Count = x.Children.Count() });
    

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

    Вот код для универсального кортежа, взятый из статья в апрельском выпуске Visual Studio Magazine .

    public struct Tuple<T1, T2> : IEquatable<Tuple<T1, T2>>
    {
        private readonly T1 first;
        public T1 First
        {
            get { return first; }
        }
    
        private readonly T2 second;
        public T2 Second
        {
            get { return second; }
        } 
    
        public Tuple(T1 f, T2 s)
        {
            first = f;
            second = s;
        }
    
        #region IEquatable<Tuple<T1,T2>> Members
        public bool Equals(Tuple<T1, T2> other)
        {
            return first.Equals(other.first) && 
                second.Equals(other.second);
        }
    
        public override bool Equals(object obj)
        {
            if (obj is Tuple<T1, T2>)
                return this.Equals((Tuple<T1, T2>)obj);
            else
                return false;
        }
    
        public override int GetHashCode()
        {
            return first.GetHashCode() ˆ second.GetHashCode();
        }
        #endregion
    }
    

    Для 1 - 2: я предпочитаю реализовать свой собственный класс кортежей. Реализация, которую вы украли, достойная. Это должно работать хорошо.

    Для 3: Вот мое эмпирическое правило - как только вы собираетесь повторно использовать эту функциональность в нескольких методах (с одинаковыми типами, имеющими одинаковое значение), или если вы используете ее в любом публичном API, я думаю, что это время для реализации «реального» класс с вашими конкретными типами.

    <Ол>
  • " Реализация класса " метод так же хорош, как и собирается (и так или иначе должен быть в следующей версии .NET)
  • Понятия не имею, я пока держу их в своей личной библиотеке классов.
  • Я бы подумал о том, чтобы создать для них подходящий класс, как только они станут доступны публике (т. е. когда они больше не будут использоваться только для внутреннего хранения связанных значений для класса).
  • Так как вы спросили мнение, мое будет состоять в том, чтобы всегда создавать тип - я не могу найти причину, чтобы этого не делать.

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

    Я думаю, что хорошо создавать новый тип, когда имеет смысл ввести новый набор значений в вашу программу. Например, если вы пишете сложный калькулятор, то создайте тип комплексного числа. Если вы действительно хотите «склеить» несколько переменных вместе на мгновение, тогда кортеж, вероятно, будет лучшим выбором. Допустим, у вас есть простая функция, которая собирает два числа с консоли ... вы можете сделать что-то вроде:

    static void GetNumbers(out int x, out int y) { ... }
    ...
    int x, y;
    GetNumbers(out x, out y);
    

    Я думаю, что обычно имеет смысл, когда " getter " Функция имеет возвращаемое значение, но в этом случае это не так, потому что я не могу иметь два возвращаемых значения. Я мог бы пойти и создать новый тип с именем TwoNumbers и использовать его, но я думаю, что это быстро становится скорее проблемой, чем решением. Если в C # есть кортежи, я могу сделать что-то вроде следующего:

    static (int, int) GetNumbers() { ... }
    ...
    int x, y;
    (x, y) = GetNumbers();
    

    Теперь действительно интересный вопрос: хотя в C # нет этой функции, могу ли я реализовать ее самостоятельно с помощью библиотеки? Код, который вы предлагаете, является началом, но не позволяет мне назначать, как я сделал во втором примере. Я не уверен насчет C #, но вы можете быть очень близки к этому в C ++, используя тот факт, что вызов функции может быть левым операндом оператора присваивания, когда его возвращаемое значение является ссылочным типом , Примите во внимание следующее:

    // this class is implemented much like yours only with C++
    template<typename T1, typename T2> class tuple { ... }
    ...
    template<typename T1, typename T2> tuple<T1, T2>& tie(T1 a, T2 b) { ... }
    ...
    template<typename T1, typename T2> tuple<T1, T2> get_numbers() { ... }
    ...
    int x, y;
    tie(x, y) = get_numbers();
    

    Я бы сказал, что это чертовски близко ... вместо (x, y) = у нас есть tie (x, y) = . Если вас интересуют подробности реализации, я отправлю вас в библиотеку TR1, где я впервые узнал об этом:

    http: //www.boost .org / док / ЛИЭС / 1_41_0 / ЛИЭС / кортеж / DOC / tuple_users_guide.html # ярусы

    Итак, чтобы вернуть все это в C # 3.0 ... мы, безусловно, можем создать универсальный класс кортежей, как вы показали, но можем ли мы создать функцию типа tie to " unpack " кортеж в C #? Я не пробовал, звучит как весело. Без чего-то подобного я бы не хотел, чтобы библиотека кортежей C # распространялась через мой код.

    Мне не нравится вывод типов в C #, так как он слишком часто используется для более короткой записи. Конечно, это очень крутая функция, но люди злоупотребляют ею ИМХО, как в этом случае.

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

    Так почему бы не иметь простой класс кортежей, который может быть реализован всего за несколько строк? И если вы ленивы, вы можете даже написать несколько методов расширения для своего класса кортежей. Это делает жизнь проще, но и чище.

    Не вижу смысла в том, чтобы иметь "причудливый" класс кортежа вместо представленного вами универсального класса (за исключением вывода типа).

    Лицензировано под: CC-BY-SA с атрибуция
    Не связан с StackOverflow
    scroll top