Nota
O acesso a esta página requer autorização. Pode tentar iniciar sessão ou alterar os diretórios.
O acesso a esta página requer autorização. Pode tentar alterar os diretórios.
A
Uma with expressão produz uma cópia de seu operando com as propriedades especificadas e os campos modificados. Use a sintaxe do inicializador de objeto para especificar quais membros modificar e seus novos 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 }
}
}
O operando esquerdo de uma with expressão pode ser de um tipo de registro. Um operando esquerdo de uma with expressão também pode ser de um tipo de estrutura ou um tipo anônimo.
O resultado de uma with expressão tem o mesmo tipo de tempo de execução que o operando da expressão, como mostra o exemplo a seguir:
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 }
}
}
Quando um membro é um tipo de referência, somente a referência a uma instância de membro é copiada quando um operando é copiado. Tanto a cópia quanto o operando original têm acesso à mesma instância de tipo de referência. O exemplo a seguir demonstra esse comportamento:
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 cópia personalizada
Qualquer tipo de classe de registro tem o construtor copy. Um construtor copy é um construtor com um único parâmetro do tipo de registro que contém. Ele copia o estado de seu argumento para uma nova instância de registro. Na avaliação de uma with expressão, o construtor copy é chamado para instanciar uma nova instância de registro com base em um registro original. Depois disso, a nova instância é atualizada de acordo com as modificações especificadas. Por padrão, o construtor copy é implícito, ou seja, gerado pelo compilador. Se você precisar personalizar a semântica da cópia de registro, declare explicitamente um construtor de cópia com o comportamento desejado. O exemplo a seguir atualiza o exemplo anterior com um construtor de cópia explícita. O novo comportamento de cópia é copiar itens de lista em vez de uma referência de lista quando um registro é copiado:
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
}
}
Não é possível personalizar a semântica de cópia para tipos de estrutura.
Importante
Nos exemplos anteriores, todas as propriedades são independentes. Nenhuma das propriedades é calculada a partir de outros valores de propriedade. Uma with expressão primeiro copia a instância de registro existente e, em seguida, modifica quaisquer propriedades ou campos especificados na with expressão. As propriedades computadas em tipos devem ser calculadas no record acesso, não inicializadas quando a instância é criada. Caso contrário, uma propriedade poderia retornar o valor calculado com base na instância original, não na cópia modificada. Para obter mais informações, consulte o artigo de referência de idioma sobre record tipos.
Especificação da linguagem C#
Para obter mais informações, consulte as seguintes seções da nota de proposta de recurso de registros: