¿Qué requisito se diseñó para resolver la tupla?

94

Estoy viendo la nueva función C # de tuplas. Tengo curiosidad, ¿qué problema se diseñó para resolver la tupla?

¿Para qué has usado tuplas en tus aplicaciones?

Actualizar

Gracias por las respuestas hasta ahora, déjame ver si tengo las cosas claras en mi mente. Se ha señalado un buen ejemplo de tupla como coordenadas. ¿Esto se ve bien?

var coords = Tuple.Create(geoLat,geoLong);

Luego usa la tupla así:

var myLatlng = new google.maps.LatLng("+ coords.Item1 + ", "+ coords.Item2 + ");

¿Es eso correcto?

Chaddeus
fuente
4
Bueno, puedo pensar en dos respuestas ...
Noon Silk
13
Si el concepto de "coordinar" tiene sentido como clase, lo convertiría en una clase. Use tuplas para aquellas situaciones donde hay no alguna sensata concepto de "lógica de negocio" para el conjunto de datos que justifica que hacen un tipo.
Eric Lippert
13
Las coordenadas no son un buen ejemplo de tupla. Tuple en C # es solo una solución ad-hoc en los casos en que tiene que devolver (desde una función) dos valores. En lugar de establecer un tipo de resultado más un parámetro de salida, es más elegante devolver una tupla. De esta forma, no es necesario que declare el segundo parámetro por adelantado. La diferencia es aún más clara en C ++ (puede const el resultado, pero no puede const el parámetro out / ref).
greenoldman
8
Porque Python lo tenía, y Python no puede tener nada que C # no tenga;)
Evan Plaice

Respuestas:

117

Al escribir programas, es muy común querer agrupar lógicamente un conjunto de valores que no tienen suficientes puntos en común para justificar la creación de una clase.

Muchos lenguajes de programación le permiten agrupar lógicamente un conjunto de valores que de otro modo no estarían relacionados sin crear un tipo de una sola manera:

void M(int foo, string bar, double blah)

Lógicamente, esto es exactamente lo mismo que un método M que toma un argumento que es una tupla 3 de int, string, double. Pero espero que en realidad no hagas:

class MArguments
{
   public int Foo { get; private set; } 
   ... etc

a menos que MArguments tuviera algún otro significado en la lógica empresarial.

El concepto de "agrupar un montón de datos que de otro modo no estarían relacionados en alguna estructura que sea más liviana que una clase" es útil en muchos, muchos lugares, no solo para listas formales de parámetros de métodos. Es útil cuando un método tiene dos cosas que devolver, o cuando desea extraer un diccionario de dos datos en lugar de uno, y así sucesivamente.

Los lenguajes como F #, que admiten tipos de tuplas de forma nativa, brindan una gran flexibilidad a sus usuarios; son un conjunto de tipos de datos extremadamente útil. El equipo de BCL decidió trabajar con el equipo de F # para estandarizar un tipo de tupla para el marco para que todos los idiomas pudieran beneficiarse de ellos.

Sin embargo, en este momento no hay soporte de lenguaje para tuplas en C #. Las tuplas son solo otro tipo de datos como cualquier otra clase de marco; no hay nada especial en ellos. Estamos considerando agregar un mejor soporte para tuplas en futuras versiones hipotéticas de C #. Si alguien tiene alguna idea sobre qué tipo de características que involucran tuplas le gustaría ver, me complacerá compartirlas con el equipo de diseño. Los escenarios realistas son más convincentes que las reflexiones teóricas.

Eric Lippert
fuente
1
@MalcomTucker: La asicronía y el paralelismo están definitivamente en nuestras mentes como áreas ricas donde las herramientas del lenguaje podrían usarse para resolver problemas reales. No creo que los flujos de trabajo asincrónicos de estilo F # sean necesariamente los más adecuados para C #, pero definitivamente son inspiradores.
Eric Lippert
60
Si bien las tuplas son útiles, un gran inconveniente es la claridad. Es difícil de leer y entender el código que se refiere a Item1, Item2, etc ... Si tuplas alguna vez lo hacen conseguir apoyo en el idioma en C #, que sería maravilloso para permitir a sus miembros a ser nombrados (o al menos un alias) de manera que permite que el código que utiliza para que sean más comprensibles. En un futuro tan hipético, también me encantaría ver tuplas de la "forma" apropiada como parámetros legales para métodos que toman parámetros individuales (y viceversa). Entonces, Tuple<int,string,bool>se puede pasar a M(int,string,bool). Facilitaría mucho los métodos de memorización.
LBushkin
2
Estas "tuplas" son básicamente todos tipos de publicacceso, anónimos struct con miembros sin nombre . Prefiero que el programador escriba un structcon miembros nombrados y devuelva eso, que tener que lidiar con un tupleque no me dice nada sobre la semántica de sus miembros.
bobobobo
1
@ Hi-Angel: El argumento no se trata de discutir sobre qué cuenta como tupla y qué no, sino sobre cuál es el conjunto de características que los desarrolladores de líneas de negocio modernas podrían usar para aumentar su productividad . LBushkin está expresando una solicitud de función que el equipo de diseño escucha todo el tiempo: el deseo de hacer un "tipo de registro" de algún tipo sin la molestia y el gasto de hacer una clase completa solo para mantener juntos algunos campos. C # ya tiene esta característica para métodos; se llama "lista de parámetros".
Eric Lippert
2
@ Hi-Angel: Probablemente no harías el argumento "si quieres acceder a los parámetros de tu método por nombre, entonces deberías crear una clase separada" porque parece extremadamente pesado, pero solo parece pesado porque estamos acostumbrados a tener el capacidad para unir instantáneamente un conjunto de variables arbitrarias con tipos y nombres arbitrarios al llamar a un método . Imagínese que ningún idioma tuviera esa característica; cada método solo podría tomar un único argumento, y si quisieras pasar dos, tendrías que hacer un tipo y pasar una instancia de él.
Eric Lippert
22

Las tuplas proporcionan una implementación inmutable de una colección

Aparte de los usos comunes de las tuplas:

  • agrupar valores comunes sin tener que crear una clase
  • para devolver múltiples valores de una función / método
  • etc ...

Los objetos inmutables son inherentemente seguros para subprocesos:

Los objetos inmutables pueden resultar útiles en aplicaciones multiproceso. Varios subprocesos pueden actuar sobre los datos representados por objetos inmutables sin preocuparse de que otros subprocesos cambien los datos. Por lo tanto, los objetos inmutables se consideran más seguros para subprocesos que los objetos mutables.

De "Objeto inmutable" en wikipedia

Evan Solla
fuente
Gracias por agregar información adicional a la pregunta. Muy apreciado.
Chaddeus
Si desea una colección inmutable, debe usar una colección inmutable, no una Tupla. La diferencia es que para la mayoría de las colecciones inmutables no es necesario especificar el número de elementos en tiempo de compilación
BlueRaja - Danny Pflughoeft
@ BlueRaja-DannyPflughoeft Cuando escribí esta respuesta, las clases de colección inmutables de C # aún no estaban disponibles en BCL. Supongo que cambiaré 'colección' a 'objeto' ya que MS neutralizó la implementación de Tuple en C #
Evan Plaice
12

Proporciona una alternativa refo outsi tiene un método que necesita devolver múltiples objetos nuevos como parte de su respuesta.

También le permite usar un tipo incorporado como tipo de retorno si todo lo que necesita hacer es combinar dos o tres tipos existentes, y no desea tener que agregar una clase / estructura solo para esta combinación. (¿Alguna vez deseó que una función pudiera devolver un tipo anónimo? Esta es una respuesta parcial a esa situación).

Toby
fuente
Maldición. Agradable. Ojalá hubiera comprobado qué son las tuplas hace unos años;).
sabiland
10

A menudo es útil tener un tipo "par", que se usa en situaciones rápidas (como devolver dos valores de un método). Las tuplas son una parte central de los lenguajes funcionales como F #, y C # las recogió en el camino.

Stephen Cleary
fuente
System.Web.UI tiene una clase de par msdn.microsoft.com/en-us/library/system.web.ui.pair.aspx .
StingyJack
5

muy útil para devolver dos valores de una función

Keith Nicholas
fuente
1
¿Quizás para envolver un tipo anónimo?
bloparod
1
Los veo como estructuras anónimas
Matt Evans
4

Personalmente, considero que Tuples es una parte iterativa del desarrollo cuando estás en un ciclo de investigación o simplemente "jugando". Debido a que una Tupla es genérica, tiendo a pensar en ella cuando trabajo con parámetros genéricos, especialmente cuando quiero desarrollar un fragmento de código genérico, y estoy comenzando por el final del código, en lugar de preguntarme "¿cómo me gustaría esta llamada ¿mirar?".

Muy a menudo me doy cuenta de que la colección que forma la Tupla se convierte en parte de una lista, y mirar List> no expresa realmente la intención de la lista, o cómo funciona. A menudo "vivo" con eso, pero me encuentro deseando manipular la lista y cambiar un valor; en ese momento, no necesariamente quiero crear una nueva Tupla para eso, por lo que necesito crear mi propia clase o estructura. para sostenerlo, para que pueda agregar código de manipulación.

Por supuesto, siempre hay métodos de extensión, pero con frecuencia no desea extender ese código adicional a implementaciones genéricas.

Ha habido ocasiones en las que he querido expresar datos como una tupla y no he tenido tuplas disponibles. (VS2008) en cuyo caso acabo de crear mi propia clase Tuple, y no la hago segura para subprocesos (inmutable).

Así que creo que soy de la opinión de que las tuplas son una programación perezosa a expensas de perder un nombre de tipo que describe su propósito. El otro gasto es que tienes que declarar la firma de la tupla siempre que se utilice como parámetro. Después de una serie de métodos que comienzan a parecer inflados, es posible que sienta, como yo, que vale la pena hacer una clase, ya que limpia las firmas del método.

Tiendo a comenzar por tener la clase como un miembro público de la clase en la que ya estás trabajando. Pero en el momento en que se extiende más allá de una simple colección de valores, obtiene su propio archivo y lo muevo fuera de la clase contenedora.

Entonces, en retrospectiva, creo que uso Tuples cuando no quiero salir y escribir una clase, y solo quiero pensar en lo que estoy escribiendo en este momento. Lo que significa que la firma de la tupla puede cambiar bastante en el texto media hora mientras averiguo qué datos necesitaré para este método y cómo devuelve los valores que devolverá.

Si tengo la oportunidad de refactorizar el código, a menudo cuestionaré el lugar de una Tupla en él.

Simon Miller
fuente
3

Antigua pregunta desde 2010, y ahora en 2017 Dotnet cambia y se vuelve más inteligente.

C # 7 introduce soporte de lenguaje para tuplas, lo que habilita nombres semánticos para los campos de una tupla usando tipos de tupla nuevos y más eficientes.

En vs 2017 y .Net 4.7 (o instalando el paquete nuget System.ValueTuple), puede crear / usar una tupla de una manera muy eficiente y sencilla:

     var person = (Id:"123", Name:"john"); //create tuble with two items
     Console.WriteLine($"{person.Id} name:{person.Name}") //access its fields

Devolver más de un valor de un método:

    public (double sum, double average) ComputeSumAndAverage(List<double> list)
    {
       var sum= list.Sum();
        var average = sum/list.Count;
        return (sum, average);
    }

    How to use:

        var list=new List<double>{1,2,3};
        var result = ComputeSumAndAverage(list);
        Console.WriteLine($"Sum={result.sum} Average={result.average}");    

Para obtener más detalles, lea: https://docs.microsoft.com/en-us/dotnet/csharp/tuples

M. Hassan
fuente
1

Una tupla se usa a menudo para devolver múltiples valores de funciones cuando no desea crear un tipo específico. Si está familiarizado con Python, Python lo ha tenido durante mucho tiempo.

Randy Minder
fuente
1

Devolver más de un valor de una función. getCoordinates () no es muy útil si solo devuelve x, yoz, pero hacer una clase y un objeto completos para contener tres entradas también parece bastante pesado.

Dean J
fuente
1

Un uso común podría ser evitar la creación de clases / estructuras que solo contengan 2 campos; en su lugar, crea una Tupla (o un KeyValuePair por ahora). Útil como valor de retorno, evite pasar N parámetros ...

user347594
fuente
0

Encuentro que KeyValuePair se actualiza en C # para iterar sobre los pares de valores clave en un diccionario.

Jubal
fuente
KeyValuePairpuede verse como una solución alternativa para un propósito especial. En Python, iterar sobre un dictsolo devuelve tuplas (clave, valor).
dan04
Sí, como Python. :-) ¿No sabía que KeyValuePair en c # no era una tupla?
Jubal
0

Es realmente útil al devolver valores de funciones. Podemos recuperar varios valores y esto es un gran ahorro en algunos escenarios.

Akshat
fuente
0

Me encontré con este punto de referencia de rendimiento entre tuplas y pares clave-valor y probablemente lo encontrará interesante. En resumen, dice que Tuple tiene ventaja porque es una clase, por lo tanto, se almacena en el montón y no en la pila y cuando se pasa como argumento, su puntero es lo único que funciona. Pero KeyValuePair es una estructura, por lo que es más rápido de asignar, pero es más lento cuando se usa.

http://www.dotnetperls.com/tuple-keyvaluepair

Ognyan Dimitrov
fuente