Descompilé algunas bibliotecas de C # 7 y vi que ValueTuple
se usaban genéricos. ¿Qué son ValueTuples
y por qué no en su Tuple
lugar?
139
Descompilé algunas bibliotecas de C # 7 y vi que ValueTuple
se usaban genéricos. ¿Qué son ValueTuples
y por qué no en su Tuple
lugar?
Respuestas:
A
ValueTuple
es una estructura que refleja una tupla, igual que laSystem.Tuple
clase original .La principal diferencia entre
Tuple
yValueTuple
son:System.ValueTuple
es un tipo de valor (estructura), mientras queSystem.Tuple
es un tipo de referencia (class
). Esto es significativo cuando se habla de asignaciones y presión de GC.System.ValueTuple
no es solo unstruct
, es mutable , y hay que tener cuidado al usarlos como tales. Piensa en lo que sucede cuando una clase tiene unSystem.ValueTuple
como un campo.System.ValueTuple
expone sus elementos a través de campos en lugar de propiedades.Hasta C # 7, usar tuplas no era muy conveniente. Sus nombres de campo son
Item1
,Item2
, azúcar sintaxis, etc, y el idioma no se había suministrado para ellos como la mayoría de otros lenguajes (Python, Scala).Cuando el equipo de diseño de lenguaje .NET decidió incorporar tuplas y agregarles azúcar de sintaxis a nivel de lenguaje, un factor importante fue el rendimiento. Al
ValueTuple
ser un tipo de valor, puede evitar la presión del GC al usarlos porque (como detalle de implementación) se asignarán en la pila.Además, a
struct
obtiene semántica de igualdad automática (superficial) por el tiempo de ejecución, donde unclass
no. Aunque el equipo de diseño se aseguró de que hubiera una igualdad aún más optimizada para las tuplas, por lo tanto, implementó una igualdad personalizada para ello.Aquí hay un párrafo de las notas de diseño de
Tuples
:Ejemplos:
Puede ver fácilmente que trabajar con se
System.Tuple
vuelve ambiguo muy rápidamente. Por ejemplo, supongamos que tenemos un método que calcula una suma y un recuento de aList<Int>
:En el extremo receptor, terminamos con:
La forma en que puede deconstruir tuplas de valor en argumentos con nombre es el poder real de la característica:
Y en el extremo receptor:
O:
Compilación de golosinas:
Si miramos debajo de la cubierta de nuestro ejemplo anterior, podemos ver exactamente cómo está interpretando el compilador
ValueTuple
cuando le pedimos que deconstruya:Internamente, el código compilado utiliza
Item1
yItem2
, pero todo esto se abstrae de nosotros ya que trabajamos con una tupla descompuesta. Una tupla con argumentos nombrados se anota con elTupleElementNamesAttribute
. Si usamos una única variable nueva en lugar de descomponernos, obtenemos:Tenga en cuenta que el compilador todavía tiene que hacer un poco de magia suceda (a través del atributo) cuando nuestra aplicación de depuración, ya que sería extraño ver
Item1
,Item2
.fuente
var (sum, count) = DoStuff(Enumerable.Range(0, 10));
La diferencia entre
Tuple
yValueTuple
es queTuple
es un tipo de referencia yValueTuple
es un tipo de valor. Esto último es deseable porque los cambios en el lenguaje en C # 7 hacen que las tuplas se usen con mucha más frecuencia, pero la asignación de un nuevo objeto en el montón para cada tupla es un problema de rendimiento, especialmente cuando no es necesario.Sin embargo, en C # 7, la idea es que nunca tenga que usar explícitamente ninguno de los tipos debido a que se agrega azúcar de sintaxis para el uso de tuplas. Por ejemplo, en C # 6, si quisiera usar una tupla para devolver un valor, tendría que hacer lo siguiente:
Sin embargo, en C # 7, puede usar esto:
Incluso puede ir un paso más allá y dar nombres a los valores:
... o deconstruir la tupla por completo:
Las tuplas no se usaban con frecuencia en C # pre-7 porque eran engorrosas y detalladas, y solo se usaban realmente en casos en los que construir una clase / estructura de datos para una sola instancia de trabajo sería más problemático de lo que valía la pena. Pero en C # 7, las tuplas tienen soporte de nivel de lenguaje ahora, por lo que usarlas es mucho más limpio y más útil.
fuente
Miré la fuente de ambos
Tuple
yValueTuple
. La diferencia es queTuple
es unclass
yValueTuple
es unstruct
que implementaIEquatable
.Eso significa que
Tuple == Tuple
se devolveráfalse
si no son la misma instancia, peroValueTuple == ValueTuple
se devolverátrue
si son del mismo tipo y seEquals
devuelvetrue
para cada uno de los valores que contienen.fuente
Otras respuestas olvidaron mencionar puntos importantes. En lugar de reformular, haré referencia a la documentación XML del código fuente :
Los tipos ValueTuple (de arity 0 a 8) comprenden la implementación en tiempo de ejecución que subyace a las tuplas en C # y las tuplas de estructura en F #.
Además de crearse mediante la sintaxis del lenguaje , se crean más fácilmente a través de los
ValueTuple.Create
métodos de fábrica. LosSystem.ValueTuple
tipos difieren de losSystem.Tuple
tipos en que:Con la introducción de este tipo y el compilador de C # 7.0, puede escribir fácilmente
Y devuelve dos valores de un método:
Al contrario
System.Tuple
, puede actualizar sus miembros (Mutable) porque son campos públicos de lectura y escritura a los que se les puede dar nombres significativos:fuente
class MyNonGenericType : MyGenericType<string, ValueTuple, int>
etc.Además de los comentarios anteriores, un inconveniente desafortunado de ValueTuple es que, como tipo de valor, los argumentos nombrados se borran cuando se compilan en IL, por lo que no están disponibles para la serialización en tiempo de ejecución.
es decir, sus argumentos con nombre dulce terminarán siendo "Item1", "Item2", etc. cuando se serialicen a través de, por ejemplo, Json.NET.
fuente
Unión tardía para agregar una aclaración rápida sobre estos dos factores:
Uno pensaría que cambiar las tuplas de valor en masa sería sencillo:
Alguien podría intentar solucionar esto así:
La razón de este comportamiento peculiar es que las tuplas de valor se basan exactamente en el valor (estructuras) y, por lo tanto, la llamada .Select (...) funciona en estructuras clonadas en lugar de en los originales. Para resolver esto debemos recurrir a:
Alternativamente, por supuesto, uno podría intentar el enfoque directo:
Espero que esto ayude a alguien que lucha por hacer cabezas de colas a partir de tuplas de valor alojadas en listas.
fuente