Melhor nomeação nas classs Tuple do que “Item1”, “Item2”

Existe uma maneira de usar uma class Tuple, mas fornecer os nomes dos itens nela?

Por exemplo:

public Tuple GetOrderRelatedIds() 

Isso retorna os IDs para OrderGroupId, OrderTypeId, OrderSubTypeId e OrderRequirementId.

Seria bom deixar os usuários do meu método saberem qual é qual. (Quando você chama o método, os resultados são result.Item1, result.Item2, result.Item3, result.Item4. Não está claro qual é qual.)

(Eu sei que eu poderia apenas criar uma class para manter todos esses IDs, mas esses IDs já têm suas próprias classs em que vivem e fazer uma class para o valor de retorno deste método parece bobo.)

No C # 7.0 (Visual Studio 2017), há uma nova construção para fazer isso:

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

Até C # 7.0, não havia como fazer isso sem definir seu próprio tipo.

Aqui está uma versão excessivamente complicada do que você está perguntando:

 class MyTuple : Tuple { public MyTuple(int one, int two) :base(one, two) { } public int OrderGroupId { get{ return this.Item1; } } public int OrderTypeId { get{ return this.Item2; } } } 

Por que não apenas fazer uma aula?

Com .net 4, você poderia talvez olhar para o ExpandoObject , no entanto, não usá-lo para este caso simples como o que teria sido erros de tempo de compilation se tornam erros de tempo de execução.

 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. 

Outra coisa que vale a pena mencionar é um tipo anônimo dentro de um método , mas você precisa criar uma class se quiser devolvê-la.

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

Se os tipos de seus itens são todos diferentes, aqui está uma aula que fiz para obtê-los de forma mais intuitiva.

O uso desta class:

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

Código fonte:

 public static class TypedTuple { public static TypedTuple Create(T1 t1) { return new TypedTuple(t1); } public static TypedTuple Create(T1 t1, T2 t2) { return new TypedTuple(t1, t2); } public static TypedTuple Create(T1 t1, T2 t2, T3 t3) { return new TypedTuple(t1, t2, t3); } public static TypedTuple Create(T1 t1, T2 t2, T3 t3, T4 t4) { return new TypedTuple(t1, t2, t3, t4); } public static TypedTuple Create(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5) { return new TypedTuple(t1, t2, t3, t4, t5); } public static TypedTuple Create(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6) { return new TypedTuple(t1, t2, t3, t4, t5, t6); } public static TypedTuple Create(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7) { return new TypedTuple(t1, t2, t3, t4, t5, t6, t7); } public static TypedTuple Create(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); } } public class TypedTuple { protected Dictionary items = new Dictionary(); public TypedTuple(T item1) { Item1 = item1; } public TSource Get() { 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 : TypedTuple { 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 : TypedTuple { 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 : TypedTuple { 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 : TypedTuple { 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 : TypedTuple { 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 : TypedTuple { 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 : TypedTuple { 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; } } } 

Não, você não pode nomear os membros da tupla.

O intermediário seria usar ExpandoObject em vez de Tuple.

Reproduzindo minha resposta deste post, pois é um ajuste melhor aqui.

Iniciando o C # v7.0 agora é possível nomear as propriedades da tupla que anteriormente usavam para padronizar nomes como Item1 , Item2 e assim por diante.

Nomeando as propriedades de Tuple Literais :

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

A saída no console:

Nome – RBT_Yoga, Idade – 22, Paixão – Dosa

Retornando Tuple (tendo propriedades nomeadas) de um método :

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

A saída no console:

Detalhes do funcionário: Rasik, Bihari, Rasik-PC, 1000

Criando uma lista de tuplas com propriedades nomeadas

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

Saída no console:

1 – vaca 5 – frangos 1 – avião

Espero ter coberto tudo. No caso, há alguma coisa que eu perdi então por favor me dê um feedback nos comentários.

Nota : Meus trechos de código estão usando o recurso de interpolação de strings do C # v7, conforme detalhado aqui .

Eu acho que criaria uma class, mas outra alternativa são os parâmetros de saída.

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

Como o seu Tuple contém apenas números inteiros, você poderia representá-lo com um Dictionary

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

mas também não recomendo.

Por que todo mundo está dificultando a vida? Tuplas são para processamento de dados bastante temporário . Trabalhar com Tuplas o tempo todo tornará o código muito difícil de entender em algum momento. Criar classs para tudo poderia eventualmente inchar seu projeto.

É sobre o equilíbrio, no entanto …

Seu problema parece ser algo pelo qual você gostaria de ter uma aula. E apenas por uma questão de completude, esta class abaixo também contém construtores.


Este é o padrão adequado para

  • Um tipo de dados personalizado
    • sem mais funcionalidades. Os getters e setters também podem ser expandidos com código, obtendo / definindo membros privados com o padrão de nome “_orderGroupId”, enquanto também executa código funcional.
  • Incluindo construtores. Você também pode optar por include apenas um construtor se todas as propriedades forem obrigatórias.
  • Se você quiser usar todos os construtores, borbulhando como este é o padrão adequado para evitar código duplicado.

 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, se você quer realmente simples: Você também pode usar inicializadores de tipo:

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

Eu escreveria os nomes dos Itens no summay .. assim, passando o mouse sobre a function helloworld (), o texto dirá ola = Item1 e world = Item2

  helloworld("Hi1,Hi2"); ///  /// Return hello = Item1 and world Item2 ///  /// string to split ///  private static Tuple 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(hello, world); } 

Isso é muito chato e espero que versões futuras do C # atendam a essa necessidade. Acho que é mais fácil trabalhar com um tipo diferente de estrutura de dados ou renomear os “itens” para sua sanidade e para a sanidade dos outros que leem seu código.

 Tuple result = await SendApiRequest(); ApiResource apiResource = result.Item1; JSendResponseStatus jSendStatus = result.Item2; 

Você pode escrever uma class que contenha o Tuple.

Você precisa replace as funções Equals e GetHashCode

e os operadores == e! =.

 class Program { public class MyTuple { private Tuple t; public MyTuple(int a, int b) { t = new Tuple(a, b); } public int A { get { return t.Item1; } } public int B { get { return t.Item2; } } public override bool Equals(object obj) { return t.Equals(((MyTuple)obj).t); } public override int GetHashCode() { return t.GetHashCode(); } public static bool operator ==(MyTuple m1, MyTuple m2) { return m1.Equals(m2); } public static bool operator !=(MyTuple m1, MyTuple m2) { return !m1.Equals(m2); } } static void Main(string[] args) { var v1 = new MyTuple(1, 2); var v2 = new MyTuple(1, 2); Console.WriteLine(v1 == v2); Dictionary d = new Dictionary(); d.Add(v1, 1); Console.WriteLine(d.ContainsKey(v2)); } } 

retornará:

Verdade

Verdade