2008-09-30 12 views

Respuesta

73

acabo de leer este artículo de la revista de MSDN: Building Tuple

Éstos son extractos:

La próxima versión 4.0 de Microsoft .NET Framework introduce un nuevo tipo denominado Sistema .Tuple. System.Tuple es una colección de tamaño fijo de datos de tipo heterogéneo.

Como una matriz, una tupla tiene un tamaño fijo que no se puede cambiar una vez que ha sido creado . A diferencia de una matriz, cada elemento en una tupla puede ser un tipo diferente , y una tupla puede garantizar tipado fuerte para cada elemento.

Ya hay un ejemplo de una tupla flota alrededor del marco Microsoft .NET , en el espacio de nombres System.Collections.Generic: KeyValuePair. Mientras KeyValuePair puede ser pensado como el mismo como tupla, ya que ambas son tipos que tienen dos cosas, KeyValuePair siente diferente de Tupla porque evoca una relación entre los dos valores que almacena (y con razón, ya que admite la clase de diccionario ).

Además, las tuplas pueden ser arbitrariamente de tamaño, mientras que KeyValuePair contiene solo dos cosas: una clave y un valor.


Mientras que algunos lenguajes como C# tienen una sintaxis especial para tuplas, se puede utilizar el nuevo tipo tupla común de cualquier idioma. Revisando el primer ejemplo, podemos ver que si bien son útiles, tuplas pueden ser demasiado prolijo en idiomas sin sintaxis de una tupla:

class Program { 
    static void Main(string[] args) { 
     Tuple<string, int> t = new Tuple<string, int>("Hello", 4); 
     PrintStringAndInt(t.Item1, t.Item2); 
    } 
    static void PrintStringAndInt(string s, int i) { 
     Console.WriteLine("{0} {1}", s, i); 
    } 
} 

El uso de la palabra clave var desde C# 3.0, podemos eliminar la firma de tipo de la variable tupla , lo que permite un código algo más legible.

var t = new Tuple<string, int>("Hello", 4); 

También hemos añadido algunos métodos de fábrica a una clase Tupla estática que hace que sea más fácil de construir tuplas en un lenguaje que soporte la inferencia de tipos, como C#.

var t = Tuple.Create("Hello", 4); 
69
#region tuples 

    public class Tuple<T> 
    { 
     public Tuple(T first) 
     { 
      First = first; 
     } 

     public T First { get; set; } 
    } 

    public class Tuple<T, T2> : Tuple<T> 
    { 
     public Tuple(T first, T2 second) 
      : base(first) 
     { 
      Second = second; 
     } 

     public T2 Second { get; set; } 
    } 

    public class Tuple<T, T2, T3> : Tuple<T, T2> 
    { 
     public Tuple(T first, T2 second, T3 third) 
      : base(first, second) 
     { 
      Third = third; 
     } 

     public T3 Third { get; set; } 
    } 

    public class Tuple<T, T2, T3, T4> : Tuple<T, T2, T3> 
    { 
     public Tuple(T first, T2 second, T3 third, T4 fourth) 
      : base(first, second, third) 
     { 
      Fourth = fourth; 
     } 

     public T4 Fourth { get; set; } 
    } 

    #endregion 

y hacer declaraciones más bonitas:

public static class Tuple 
{ 
    //Allows Tuple.New(1, "2") instead of new Tuple<int, string>(1, "2") 
    public static Tuple<T1, T2> New<T1, T2>(T1 t1, T2 t2) 
    { 
     return new Tuple<T1, T2>(t1, t2); 
    } 
    //etc... 
} 
+1

Si bien la cuestión está en MS proporcionando en .NET 4, esta es una buena forma de administrarlo por ahora. +1 –

+6

Este enfoque de herencia está bien si no necesita comparar dos tuplas para la igualdad. Quería implementar IEquatable > y demás en mi implementación, por lo que no pude usar la herencia, porque no quería que un Tuple fuera igual a un Tuple . –

+3

@Joel, puede hacer que Equals compruebe el tipo dinámico de ambos argumentos. – RossFabricant

2

Si no recuerdo mis clases de informática correctamente tuplas son sólo datos.

Si desea datos agrupados, cree clases que contengan propiedades. Si necesita algo como el KeyValuePair, ahí está.

+2

Al igual que si las declaraciones son simplemente gotos con un bloque de declaraciones.Las tuplas son agradables si tienes que estás acostumbrado a ellas y las clases parecen innecesarias e inmanejables en casos específicos ... –

0

Me sorprendería que C# sea un lenguaje fuertemente tipado, mientras que las tuplas son adecuadas para lenguajes de tipado más dinámico. C# ha ido a la deriva más dinámico a medida que pasa el tiempo, pero eso es azúcar sintáctica, no un cambio real en los tipos de datos subyacentes.

Si quiere dos valores en una instancia, un KeyValuePair <> es un sustituto decente, aunque torpe. También puede crear una estructura o una clase que haga lo mismo y que sea ampliable.

+2

"C# ha sido más dinámico" - no, ha estado derivando más implícito/inferido; todavía es un lenguaje completamente estático. Sin embargo, un mejor soporte dinámico (para consumir clases de DLR) es una mejora de lenguaje futura muy probable. –

+2

¿Cómo se explica la presencia de tuplas en F #, Haskell o cualquiera de los otros lenguajes fuertemente tipificados y estáticos que tienen soporte completo para ellos, entonces ...? –

12

En mi opinión, la característica de tipos anónimos no es una tupla, sino una construcción muy similar. El resultado de algunas consultas LINQ son colecciones de tipos anónimos, que se comportan como tuplas.

Aquí es una declaración, lo que crea una tupla :-) mecanografiada sobre la marcha:

var p1 = new {a = "A", b = 3}; 

véase: http://www.developer.com/net/csharp/article.php/3589916

3

C# soporta tuplas simples a través de los genéricos con bastante facilidad (como en una respuesta anterior) , y con "tipeo silencioso" (una de las muchas mejoras posibles del lenguaje C#) para mejorar la inferencia de tipo, podrían ser muy, muy poderosos.

Por lo que vale la pena, F # soporta de forma nativa tuplas, y después de haber jugado con él, no estoy seguro de que las tuplas (anónimo) añaden mucho ... lo que ganas en la brevedad se pierde muy rápidamente en la claridad del código .

Para el código dentro de un único método, hay tipos anónimos; para el código que va fuera de un método, creo que me atengo a los tipos con nombre simple. Por supuesto, si un futuro C# hace que sea más fácil hacerlos inmutables (aunque sea fácil trabajar con él), seré feliz.

+0

Uno de los beneficios es para cosas como TryParse, donde puede escribir 'valor válido = double.TryParse ("1.02")' y tiene múltiples valores de retorno asignados sin ningún tipo de parámetros torpes. Pero, en general, estoy de acuerdo en que las estructuras de datos puramente posicionales no son una gran cosa para transmitir. –

+2

De acuerdo: los valores de devolución múltiples son el mejor caso de uso para las tuplas, y aparte de eso, hay muy poco propósito para las tuplas en el código. Eso debería ser una convención en lugar de una restricción, aunque se permiten las tuplas. Lo que creo que hubiera sido mejor es si los lenguajes .NET proporcionan una forma de "diseccionar" objetos de retorno en múltiples valores en lugar de introducir el tipo de datos de tupla. Algo como '{j = ErrorCode, h = ResultObj} = SomeFunction()' (donde 'j' y' h' son locales) hubiera sido mucho más útil que las tuplas. –

14

La implementación de clases Tuple o la reutilización de clases F # dentro de C# es solo la mitad de la historia. Éstas le dan la capacidad de crear tuplas con relativa facilidad, pero no el azúcar sintáctico que las hace tan agradables en idiomas como F #.

Por ejemplo, en C# puede utilizar coincidencia de patrones para extraer las dos partes de una tupla dentro de un DECLARACIÓN let, por ejemplo

let (a, b) = someTupleFunc 

Desafortunadamente para hacer lo mismo usando las clases # F de C# sería mucho menos elegante:

Tuple<int,int> x = someTupleFunc(); 
int a = x.get_Item1(); 
int b = x.get_Item2(); 

tuplas representan un poderoso método para devolver varios valores de una llamada de función sin la necesidad de la basura su código con clases de usar y tirar, o recurrir a la fea ref o fuera parámetros.Sin embargo, en mi opinión, sin azúcar sintáctico para hacer que su creación y acceso sean más elegantes, tienen un uso limitado.

+0

¿Qué tal los tipos anónimos, entonces? –

+0

Eso le permite reemplazar Tuple con var, pero aún así termina con tres líneas de código en lugar de uno –

+0

Quizás esto es algo que veremos en C# 4.0. Azúcar sintáctico como int a, b = someTupleFunc(); debería ser perfectamente factible a nivel de compilador. –

0

Para hacer que esto sea útil en una tabla hash o diccionario, es probable que desee proporcionar sobrecargas para GetHashCode e Igual.

2

Aquí está mi conjunto de tuplas, son generados automáticamente por un script en Python, así que quizás he ido un poco por la borda:

Link to Subversion repository

Usted necesitará un nombre de usuario/contraseña, que están tanto invitados

se basan en la herencia, pero no Tuple<Int32,String> compararán igual a Tuple<Int32,String,Boolean> incluso si sucede que tiene los mismos valores para los dos primeros miembros.

También implementan GetHashCode y ToString, entre otros, y muchos métodos pequeños de ayuda.

Ejemplo de uso:

Tuple<Int32, String> t1 = new Tuple<Int32, String>(10, "a"); 
Tuple<Int32, String, Boolean> t2 = new Tuple<Int32, String, Boolean>(10, "a", true); 
if (t1.Equals(t2)) 
    Console.Out.WriteLine(t1 + " == " + t2); 
else 
    Console.Out.WriteLine(t1 + " != " + t2); 

seria:

10, a != 10, a, True 
+0

Pero eso no es todo. Si se basa en la herencia, supongo que podría escribir 'Tuple t1 = new Tuple (10," a ", true);' etc. No estoy seguro de que haya es cualquier escenario que se desee – nawfal

15

Existe una adecuada (no rápida) C# Tupla aplicación en Lokad Shared Libraries (de código abierto, por supuesto) que incluye las siguientes características requeridas:

  • 2-5 implementaciones de tupla inmutables
  • DebuggerDisplayAttribute Proper
  • hashing y de igualdad adecuados controles
  • ayudantes para la generación de tuplas de los parámetros proporcionados (genéricos se infieren por compilador) y extensiones para operaciones basadas en de recogida.
  • probado en producción.
3

Mi código abierto .NET Sasa library ha tenido tuplas durante años (junto con un montón de otras funcionalidades, como el análisis de MIME completo). Lo he estado utilizando en el código de producción durante unos años.

3

C# 7 soporta tuplas nativa:

var unnamedTuple = ("Peter", 29); 
var namedTuple = (Name: "Peter", Age: 29); 
(string Name, double Age) typedTuple = ("Peter", 29); 
+0

Esto funciona fuera de la caja a partir de _.NET 4.7_, ya que las versiones anteriores de .NET no contienen las estructuras necesarias de 'ValueTuple'. Sin embargo, puede proporcionar estos, por ejemplo, mediante un paquete NuGet como [ValueTupleBridge] (https://www.nuget.org/packages/ValueTupleBridge/). – tm1

Cuestiones relacionadas