Nota:
El acceso a esta página requiere autorización. Puede intentar iniciar sesión o cambiar directorios.
El acceso a esta página requiere autorización. Puede intentar cambiar los directorios.
La
Una with expresión genera una copia de su operando con las propiedades y campos especificados modificados. Use la sintaxis del inicializador de objetos para especificar qué miembros modificar y sus nuevos valores:
using System;
public class WithExpressionBasicExample
{
public record NamedPoint(string Name, int X, int Y);
public static void Main()
{
var p1 = new NamedPoint("A", 0, 0);
Console.WriteLine($"{nameof(p1)}: {p1}"); // output: p1: NamedPoint { Name = A, X = 0, Y = 0 }
var p2 = p1 with { Name = "B", X = 5 };
Console.WriteLine($"{nameof(p2)}: {p2}"); // output: p2: NamedPoint { Name = B, X = 5, Y = 0 }
var p3 = p1 with
{
Name = "C",
Y = 4
};
Console.WriteLine($"{nameof(p3)}: {p3}"); // output: p3: NamedPoint { Name = C, X = 0, Y = 4 }
Console.WriteLine($"{nameof(p1)}: {p1}"); // output: p1: NamedPoint { Name = A, X = 0, Y = 0 }
var apples = new { Item = "Apples", Price = 1.19m };
Console.WriteLine($"Original: {apples}"); // output: Original: { Item = Apples, Price = 1.19 }
var saleApples = apples with { Price = 0.79m };
Console.WriteLine($"Sale: {saleApples}"); // output: Sale: { Item = Apples, Price = 0.79 }
}
}
El operando izquierdo de una with expresión puede ser de un tipo de registro. Un operando izquierdo de una with expresión también puede ser de un tipo de estructura o un tipo anónimo.
El resultado de una with expresión tiene el mismo tipo en tiempo de ejecución que el operando de la expresión, como se muestra en el ejemplo siguiente:
using System;
public class InheritanceExample
{
public record Point(int X, int Y);
public record NamedPoint(string Name, int X, int Y) : Point(X, Y);
public static void Main()
{
Point p1 = new NamedPoint("A", 0, 0);
Point p2 = p1 with { X = 5, Y = 3 };
Console.WriteLine(p2 is NamedPoint); // output: True
Console.WriteLine(p2); // output: NamedPoint { X = 5, Y = 3, Name = A }
}
}
Cuando un miembro es un tipo de referencia, solo se copia la referencia a una instancia de miembro cuando se copia un operando. Tanto el operando copy como el original tienen acceso a la misma instancia de tipo de referencia. En el ejemplo siguiente se muestra ese comportamiento:
using System;
using System.Collections.Generic;
public class ExampleWithReferenceType
{
public record TaggedNumber(int Number, List<string> Tags)
{
public string PrintTags() => string.Join(", ", Tags);
}
public static void Main()
{
var original = new TaggedNumber(1, new List<string> { "A", "B" });
var copy = original with { Number = 2 };
Console.WriteLine($"Tags of {nameof(copy)}: {copy.PrintTags()}");
// output: Tags of copy: A, B
original.Tags.Add("C");
Console.WriteLine($"Tags of {nameof(copy)}: {copy.PrintTags()}");
// output: Tags of copy: A, B, C
}
}
Semántica de copia personalizada
Cualquier tipo de clase de registro tiene el constructor copy. Un constructor de copia es un constructor con un único parámetro del tipo de registro contenedor. Copia el estado de su argumento en una nueva instancia de registro. En la evaluación de una with expresión, se llama al constructor de copia para crear instancias de una nueva instancia de registro basada en un registro original. Después, la nueva instancia se actualiza según las modificaciones especificadas. De forma predeterminada, el constructor de copia es implícito, es decir, generado por el compilador. Si necesita personalizar la semántica de copia de registros, declare explícitamente un constructor de copia con el comportamiento deseado. En el ejemplo siguiente se actualiza el ejemplo anterior con un constructor de copia explícito. El nuevo comportamiento de copia consiste en copiar elementos de lista en lugar de una referencia de lista cuando se copia un registro:
using System;
using System.Collections.Generic;
public class UserDefinedCopyConstructorExample
{
public record TaggedNumber(int Number, List<string> Tags)
{
protected TaggedNumber(TaggedNumber original)
{
Number = original.Number;
Tags = new List<string>(original.Tags);
}
public string PrintTags() => string.Join(", ", Tags);
}
public static void Main()
{
var original = new TaggedNumber(1, new List<string> { "A", "B" });
var copy = original with { Number = 2 };
Console.WriteLine($"Tags of {nameof(copy)}: {copy.PrintTags()}");
// output: Tags of copy: A, B
original.Tags.Add("C");
Console.WriteLine($"Tags of {nameof(copy)}: {copy.PrintTags()}");
// output: Tags of copy: A, B
}
}
No se puede personalizar la semántica de copia para los tipos de estructura.
Importante
En los ejemplos anteriores, todas las propiedades son independientes. Ninguna de las propiedades se calcula desde otros valores de propiedad. Una with expresión copia primero la instancia de registro existente y, a continuación, modifica las propiedades o campos especificados en la with expresión. Las propiedades calculadas de record los tipos deben calcularse en el acceso, sin inicializarse cuando se crea la instancia. De lo contrario, una propiedad podría devolver el valor calculado en función de la instancia original, no la copia modificada. Para obtener más información, consulte el artículo de referencia del lenguaje sobre record tipos.
Especificación del lenguaje C#
Para obtener más información, consulte las secciones siguientes de la nota de propuesta de características de registros: