Лучшее наименование в классах Tuple, чем "Item1", "Item2" - PullRequest
164 голосов
/ 13 октября 2011

Есть ли способ использовать класс Tuple, но указать названия предметов в нем?

Например:

public Tuple<int, int, int int> GetOrderRelatedIds()

Возвращает идентификаторы для OrderGroupId, OrderTypeId, OrderSubTypeId и OrderRequirementId.

Было бы неплохо, чтобы пользователи моего метода знали, что есть что. (Когда вы вызываете метод, результатом являются result.Item1, result.Item2, result.Item3, result.Item4. Не ясно, какой из них какой.)

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

Ответы [ 13 ]

216 голосов
/ 13 октября 2016

В C # 7.0 (Visual Studio 2017) для этого есть новая конструкция:

(string first, string middle, string last) LookupName(long id)
50 голосов
/ 13 октября 2011

До C # 7.0 не было никакого способа сделать это, кроме определения вашего собственного типа.

31 голосов
/ 13 октября 2011

Вот слишком сложная версия того, что вы спрашиваете:

class MyTuple : Tuple<int, int>
{
    public MyTuple(int one, int two)
        :base(one, two)
    {

    }

    public int OrderGroupId { get{ return this.Item1; } }
    public int OrderTypeId { get{ return this.Item2; } }

}

Почему бы просто не сделать урок?

12 голосов
/ 13 октября 2011

С .net 4 вы, возможно, могли бы взглянуть на ExpandoObject, однако, не используйте его для этого простого случая, поскольку ошибки во время компиляции становятся ошибками во время выполнения.

class Program
{
    static void Main(string[] args)
    {
        dynamic employee, manager;

        employee = new ExpandoObject();
        employee.Name = "John Smith";
        employee.Age = 33;

        manager = new ExpandoObject();
        manager.Name = "Allison Brown";
        manager.Age = 42;
        manager.TeamSize = 10;

        WritePerson(manager);
        WritePerson(employee);
    }
    private static void WritePerson(dynamic person)
    {
        Console.WriteLine("{0} is {1} years old.",
                          person.Name, person.Age);
        // The following statement causes an exception
        // if you pass the employee object.
        // Console.WriteLine("Manages {0} people", person.TeamSize);
    }
}
// This code example produces the following output:
// John Smith is 33 years old.
// Allison Brown is 42 years old.

Стоит упомянуть еще один анонимный тип 1009 * для метода , но вам нужно создать класс, если вы хотите его вернуть.

var MyStuff = new
    {
        PropertyName1 = 10,
        PropertyName2 = "string data",
        PropertyName3 = new ComplexType()
    };
3 голосов
/ 01 мая 2019

MichaelMocko ответил отлично,

но я хочу добавить несколько вещей, которые мне пришлось выяснить

(string first, string middle, string last) LookupName(long id)

выше строки даст вам ошибку времени компиляции , если вы используете .net framework <4.7 </strong>

Так что, если у вас есть проект, использующий .net framework <4.7 </strong> и все же вы хотите использовать ValueTuple, чем workAround будет устанавливать этот пакет nuget

3 голосов
/ 24 января 2014

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

Использование этого класса:

var t = TypedTuple.Create("hello", 1, new MyClass());
var s = t.Get<string>();
var i = t.Get<int>();
var c = t.Get<MyClass>();

Исходный код:

public static class TypedTuple
{
    public static TypedTuple<T1> Create<T1>(T1 t1)
    {
        return new TypedTuple<T1>(t1);
    }

    public static TypedTuple<T1, T2> Create<T1, T2>(T1 t1, T2 t2)
    {
        return new TypedTuple<T1, T2>(t1, t2);
    }

    public static TypedTuple<T1, T2, T3> Create<T1, T2, T3>(T1 t1, T2 t2, T3 t3)
    {
        return new TypedTuple<T1, T2, T3>(t1, t2, t3);
    }

    public static TypedTuple<T1, T2, T3, T4> Create<T1, T2, T3, T4>(T1 t1, T2 t2, T3 t3, T4 t4)
    {
        return new TypedTuple<T1, T2, T3, T4>(t1, t2, t3, t4);
    }

    public static TypedTuple<T1, T2, T3, T4, T5> Create<T1, T2, T3, T4, T5>(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5)
    {
        return new TypedTuple<T1, T2, T3, T4, T5>(t1, t2, t3, t4, t5);
    }

    public static TypedTuple<T1, T2, T3, T4, T5, T6> Create<T1, T2, T3, T4, T5, T6>(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6)
    {
        return new TypedTuple<T1, T2, T3, T4, T5, T6>(t1, t2, t3, t4, t5, t6);
    }

    public static TypedTuple<T1, T2, T3, T4, T5, T6, T7> Create<T1, T2, T3, T4, T5, T6, T7>(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7)
    {
        return new TypedTuple<T1, T2, T3, T4, T5, T6, T7>(t1, t2, t3, t4, t5, t6, t7);
    }

    public static TypedTuple<T1, T2, T3, T4, T5, T6, T7, T8> Create<T1, T2, T3, T4, T5, T6, T7, T8>(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7, T8 t8)
    {
        return new TypedTuple<T1, T2, T3, T4, T5, T6, T7, T8>(t1, t2, t3, t4, t5, t6, t7, t8);
    }

}

public class TypedTuple<T>
{
    protected Dictionary<Type, object> items = new Dictionary<Type, object>();

    public TypedTuple(T item1)
    {
        Item1 = item1;
    }

    public TSource Get<TSource>()
    {
        object value;
        if (this.items.TryGetValue(typeof(TSource), out value))
        {
            return (TSource)value;
        }
        else
            return default(TSource);
    }

    private T item1;
    public T Item1 { get { return this.item1; } set { this.item1 = value; this.items[typeof(T)] = value; } }
}

public class TypedTuple<T1, T2> : TypedTuple<T1>
{
    public TypedTuple(T1 item1, T2 item2)
        : base(item1)
    {
        Item2 = item2;
    }

    private T2 item2;
    public T2 Item2 { get { return this.item2; } set { this.item2 = value; this.items[typeof(T2)] = value; } }
}

public class TypedTuple<T1, T2, T3> : TypedTuple<T1, T2>
{
    public TypedTuple(T1 item1, T2 item2, T3 item3)
        : base(item1, item2)
    {
        Item3 = item3;
    }

    private T3 item3;
    public T3 Item3 { get { return this.item3; } set { this.item3 = value; this.items[typeof(T3)] = value; } }
}

public class TypedTuple<T1, T2, T3, T4> : TypedTuple<T1, T2, T3>
{
    public TypedTuple(T1 item1, T2 item2, T3 item3, T4 item4)
        : base(item1, item2, item3)
    {
        Item4 = item4;
    }

    private T4 item4;
    public T4 Item4 { get { return this.item4; } set { this.item4 = value; this.items[typeof(T4)] = value; } }
}

public class TypedTuple<T1, T2, T3, T4, T5> : TypedTuple<T1, T2, T3, T4>
{
    public TypedTuple(T1 item1, T2 item2, T3 item3, T4 item4, T5 item5)
        : base(item1, item2, item3, item4)
    {
        Item5 = item5;
    }

    private T5 item5;
    public T5 Item5 { get { return this.item5; } set { this.item5 = value; this.items[typeof(T5)] = value; } }
}

public class TypedTuple<T1, T2, T3, T4, T5, T6> : TypedTuple<T1, T2, T3, T4, T5>
{
    public TypedTuple(T1 item1, T2 item2, T3 item3, T4 item4, T5 item5, T6 item6)
        : base(item1, item2, item3, item4, item5)
    {
        Item6 = item6;
    }

    private T6 item6;
    public T6 Item6 { get { return this.item6; } set { this.item6 = value; this.items[typeof(T6)] = value; } }
}

public class TypedTuple<T1, T2, T3, T4, T5, T6, T7> : TypedTuple<T1, T2, T3, T4, T5, T6>
{
    public TypedTuple(T1 item1, T2 item2, T3 item3, T4 item4, T5 item5, T6 item6, T7 item7)
        : base(item1, item2, item3, item4, item5, item6)
    {
        Item7 = item7;
    }

    private T7 item7;
    public T7 Item7 { get { return this.item7; } set { this.item7 = value; this.items[typeof(T7)] = value; } }
}

public class TypedTuple<T1, T2, T3, T4, T5, T6, T7, T8> : TypedTuple<T1, T2, T3, T4, T5, T6, T7>
{
    public TypedTuple(T1 item1, T2 item2, T3 item3, T4 item4, T5 item5, T6 item6, T7 item7, T8 item8)
        : base(item1, item2, item3, item4, item5, item6, item7)
    {
        Item8 = item8;
    }

    private T8 item8;
    public T8 Item8 { get { return this.item8; } set { this.item8 = value; this.items[typeof(T8)] = value; } }
}
2 голосов
/ 30 мая 2018

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

Начиная с C # v7.0, теперь можно присваивать имена свойств кортежа, которые ранее использовались по умолчанию, именаминапример Item1, Item2 и т. д.

Именование свойств литералов кортежей :

var myDetails = (MyName: "RBT_Yoga", MyAge: 22, MyFavoriteFood: "Dosa");
Console.WriteLine($"Name - {myDetails.MyName}, Age - {myDetails.MyAge}, Passion - {myDetails.MyFavoriteFood}");

Вывод на консоль:

Имя - RBT_Yoga, Возраст - 22, Страсть - Dosa

Возвращение кортежа (с именованными свойствами) из метода :

static void Main(string[] args)
{
    var empInfo = GetEmpInfo();
    Console.WriteLine($"Employee Details: {empInfo.firstName}, {empInfo.lastName}, {empInfo.computerName}, {empInfo.Salary}");
}

static (string firstName, string lastName, string computerName, int Salary) GetEmpInfo()
{
    //This is hardcoded just for the demonstration. Ideally this data might be coming from some DB or web service call
    return ("Rasik", "Bihari", "Rasik-PC", 1000);
}

Вывод на консоль:

Сведения о сотруднике: Rasik, Bihari, Rasik-PC, 1000

Создание списка кортежей с именованными свойствами

var tupleList = new List<(int Index, string Name)>
{
    (1, "cow"),
    (5, "chickens"),
    (1, "airplane")
};

foreach (var tuple in tupleList)
    Console.WriteLine($"{tuple.Index} - {tuple.Name}");

Вывод на консоль:

1 - корова 5 - цыплята 1 - самолет

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

Примечание : мои фрагменты кода используют функцию интерполяции строк C # v7, как подробно здесь .

2 голосов
/ 13 октября 2011

Нет, вы не можете назвать членов кортежа.

Промежуточный интервал будет использовать ExpandoObject вместо Tuple.

1 голос
/ 28 октября 2016

Это очень раздражает, и я ожидаю, что будущие версии C # решат эту проблему.Я считаю, что проще всего использовать другой тип структуры данных или переименовать «элементы» для вашего здравого смысла и для здравомыслия других, читающих ваш код.

0 голосов
/ 12 октября 2016

Я бы написал названия предметов в резюме. поэтому при наведении указателя мыши на функцию helloworld () текст будет отображать hello = Item1 и world = Item2

 helloworld("Hi1,Hi2");

/// <summary>
/// Return hello = Item1 and world Item2
/// </summary>
/// <param name="input">string to split</param>
/// <returns></returns>
private static Tuple<bool, bool> helloworld(string input)
{
    bool hello = false;
    bool world = false;
    foreach (var hw in input.Split(','))
    {
        switch (hw)
        {
            case "Hi1":
                hello= true;
                break;
            case "Hi2":
                world= true;
                break;
        }

    }
    return new Tuple<bool, bool>(hello, world);
}
...