Descompilé algunas bibliotecas de C # 7 y vi que ValueTuplese usaban genéricos. ¿Qué son ValueTuplesy por qué no en su Tuplelugar?
139
Descompilé algunas bibliotecas de C # 7 y vi que ValueTuplese usaban genéricos. ¿Qué son ValueTuplesy por qué no en su Tuplelugar?
Respuestas:
A
ValueTuplees una estructura que refleja una tupla, igual que laSystem.Tupleclase original .La principal diferencia entre
TupleyValueTupleson:System.ValueTuplees un tipo de valor (estructura), mientras queSystem.Tuplees un tipo de referencia (class). Esto es significativo cuando se habla de asignaciones y presión de GC.System.ValueTupleno es solo unstruct, es mutable , y hay que tener cuidado al usarlos como tales. Piensa en lo que sucede cuando una clase tiene unSystem.ValueTuplecomo un campo.System.ValueTupleexpone 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
ValueTupleser 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
structobtiene semántica de igualdad automática (superficial) por el tiempo de ejecución, donde unclassno. 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.Tuplevuelve 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
ValueTuplecuando le pedimos que deconstruya:Internamente, el código compilado utiliza
Item1yItem2, 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
TupleyValueTuplees queTuplees un tipo de referencia yValueTuplees 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
TupleyValueTuple. La diferencia es queTuplees unclassyValueTuplees unstructque implementaIEquatable.Eso significa que
Tuple == Tuplese devolveráfalsesi no son la misma instancia, peroValueTuple == ValueTuplese devolverátruesi son del mismo tipo y seEqualsdevuelvetruepara 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.Createmétodos de fábrica. LosSystem.ValueTupletipos difieren de losSystem.Tupletipos 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