web-dev-qa-db-fra.com

Mieux nommer dans les classes Tuple que "Item1", "Item2"

Existe-t-il un moyen d'utiliser une classe Tuple tout en fournissant le nom des éléments qu'il contient?

Par exemple:

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

Cela renvoie les identifiants de OrderGroupId, OrderTypeId, OrderSubTypeId et OrderRequirementId.

Ce serait bien de laisser savoir aux utilisateurs de ma méthode qui est qui. (Lorsque vous appelez la méthode, les résultats sont result.Item1, result.Item2, result.Item3, result.Item4. Il est difficile de savoir lequel est lequel.)

(Je sais que je pourrais simplement créer une classe pour contenir tous ces identifiants, mais si ces identifiants ont déjà leurs propres classes dans lesquelles ils vivent et créer une classe pour la valeur de retour de cette méthode semble ridicule.)

171
Vaccano

En C # 7.0 (Visual Studio 2017), une nouvelle construction permet de le faire:

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

Jusqu'en C # 7.0, il n'y avait aucun moyen de le faire si vous ne définissiez pas votre propre type.

52
MarkPflug

Voici une version trop compliquée de ce que vous demandez:

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

}

Pourquoi ne pas simplement faire un cours?

32
scottm

Avec .net 4, vous pourriez peut-être regarder ExpandoObject , mais ne l'utilisez pas pour ce cas simple, car ce qui aurait été une erreur de compilation devient une erreur d'exécution.

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.

Une autre chose à noter est un type anonyme pour une méthode , mais vous devez créer une classe si vous voulez retourner il.

var MyStuff = new
    {
        PropertyName1 = 10,
        PropertyName2 = "string data",
        PropertyName3 = new ComplexType()
    };
12
George Duckett

Reproduire ma réponse de this post car cela s’adapte mieux ici.

À partir de C # v7.0, il est maintenant possible de nommer les propriétés de tuple utilisées auparavant par défaut avec des noms tels que Item1, Item2, etc.

Nommer les propriétés des littéraux simples :

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

La sortie sur console:

Nom - RBT_Yoga, Age - 22, Passion - Dosa

Renvoyer un tuple (ayant des propriétés nommées) depuis une méthode :

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

La sortie sur console:

Renseignements sur l'employé: Rasik, Bihari, Rasik-PC, 1000

Création d'une liste de nuplets ayant des propriétés nommées

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

Sortie sur console:

1 - vache 5 - poulets 1 - avion

J'espère avoir tout couvert. Dans le cas où il y a quelque chose que j'ai manqué alors s'il vous plaît donnez-moi un retour dans les commentaires.

Remarque : Mes extraits de code utilisent la fonction d'interpolation de chaîne de C # v7 de manière détaillée ici .

4
RBT

Si les types de vos articles sont tous différents, voici un cours que j'ai conçu pour les obtenir de manière plus intuitive.

L'utilisation de cette classe:

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

Code source:

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

MichaelMocko a répondu est super,

mais je veux ajouter quelques choses que je devais comprendre

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

au-dessus de Ligne, vous obtiendrez une erreur de compilation si vous utilisez .net framework <4.7

Donc, si vous avez un projet qui utilise . Net framework <4.7 et que vous voulez quand même utiliser ValueTuple, ce que workAround installerait this paquet de nugets

3
Mihir Dave

Non, vous ne pouvez pas nommer les membres de Tuple.

L'entre-deux serait d'utiliser ExpandoObject au lieu de Tuple.

2
Joe Mancuso

C’est très agaçant et j’espère que les futures versions de C # répondront à ce besoin. La solution la plus simple consiste à utiliser un type de structure de données différent ou à renommer les "éléments" pour votre santé mentale et celle des autres lecteurs de votre code.

Tuple<ApiResource, JSendResponseStatus> result = await SendApiRequest();
ApiResource apiResource = result.Item1;
JSendResponseStatus jSendStatus = result.Item2;
1
Mitch Stewart

Je pense que je créerais une classe mais une autre alternative est les paramètres de sortie.

public void GetOrderRelatedIds(out int OrderGroupId, out int OrderTypeId, out int OrderSubTypeId, out int OrderRequirementId)

Comme votre tuple ne contient que des entiers, vous pouvez le représenter avec un Dictionary<string,int>

var orderIds = new Dictionary<string, int> {
    {"OrderGroupId", 1},
    {"OrderTypeId", 2},
    {"OrderSubTypeId", 3},
    {"OrderRequirementId", 4}.
};

mais je ne le recommande pas non plus.

0
Jonas Elfström

J'écrirais les noms des éléments dans la synthèse .. donc en survolant la fonction helloworld () le texte dira hello = Item1 et 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);
}
0
Kim Yang Jacobsen

Pourquoi tout le monde rend la vie si difficile. Les tuples sont plutôt pour données temporaires traitement. Travailler avec Tuples tout le temps rendra le code très difficile à comprendre à un moment donné. La création de classes pour tout pourrait éventuellement alourdir votre projet.

C'est à propos de l'équilibre, cependant ...

Votre problème semble être quelque chose pour lequel vous voudriez un cours. Et juste pour être complet, cette classe ci-dessous contient également des constructeurs.


C’est le bon modèle pour

  • Un type de données personnalisé
    • sans autre fonctionnalité. Les getters et les setters peuvent également être étendus avec du code, obtenant/définissant des membres privés avec le motif de nom "_orderGroupId", tout en exécutant du code fonctionnel.
  • Y compris les constructeurs. Vous pouvez également choisir d'inclure un seul constructeur si les propriétés all sont obligatoires.
  • Si vous souhaitez utiliser tous les constructeurs, le bouillonnement de ce type constitue le modèle approprié pour éviter la duplication de code.

public class OrderRelatedIds
{
    public int OrderGroupId { get; set; }
    public int OrderTypeId { get; set; }
    public int OrderSubTypeId { get; set; }
    public int OrderRequirementId { get; set; }

    public OrderRelatedIds()
    {
    }
    public OrderRelatedIds(int orderGroupId)
        : this()
    {
        OrderGroupId = orderGroupId;
    }
    public OrderRelatedIds(int orderGroupId, int orderTypeId)
        : this(orderGroupId)
    {
        OrderTypeId = orderTypeId;
    }
    public OrderRelatedIds(int orderGroupId, int orderTypeId, int orderSubTypeId)
        : this(orderGroupId, orderTypeId)
    {
        OrderSubTypeId = orderSubTypeId;
    }
    public OrderRelatedIds(int orderGroupId, int orderTypeId, int orderSubTypeId, int orderRequirementId)
        : this(orderGroupId, orderTypeId, orderSubTypeId)
    {
        OrderRequirementId = orderRequirementId;
    }
}

Ou, si vous voulez que ce soit vraiment simple: Vous pouvez également utiliser des initialiseurs de type:

OrderRelatedIds orders = new OrderRelatedIds
{
    OrderGroupId = 1,
    OrderTypeId = 2,
    OrderSubTypeId = 3,
    OrderRequirementId = 4
};

public class OrderRelatedIds
{
    public int OrderGroupId;
    public int OrderTypeId;
    public int OrderSubTypeId;
    public int OrderRequirementId;
}
0
bytecode77