Empresas
Empleos
  • Sobre nosotros
  • Soluciones
    • Publicación de vacantes
      Publica tu vacante y recibe candidatos calificados en 48h.
    • Evaluación de candidatos
      500+ pruebas técnicas y psicológicas, más anti-fraude.
    • Headhunting
      Búsqueda ejecutiva a la medida de principio a fin.
    • Nómina + EOR
      Dispersión de nómina y EOR en más de 15 países de LATAM.
  • Precios
  • Empleos

0

220
Vistas
¿Ignorar campos específicos cuando se usa "con" en un registro de C# 9?

Al crear una nueva instancia de un record de C# 9 mediante la palabra clave with , me gustaría ignorar algunos campos en lugar de copiarlos también en la nueva instancia.

En el siguiente ejemplo, tengo una propiedad Hash . Debido a que es muy costoso en computación, solo se calcula cuando es necesario y luego se almacena en caché (tengo un registro profundamente inmutable, por lo que el hash nunca cambiará para una instancia).

 public record MyRecord { // All truely immutable properties public int ThisAndManyMoreComplicatedProperties { get; init; } // ... // Compute only when required, but then cache it public string Hash { get { if (hash == null) hash = ComputeHash(); return hash; } } private string? hash = null; }

al llamar

 MyRecord myRecord = ...; var changedRecord = myRecord with { AnyProp = ... };

changedRecord contiene el valor hash de myRecord , pero lo que quiero tener es el valor predeterminado null nuevamente.

¿Alguna posibilidad de marcar el campo hash como "transitorio"/"interno"/"realmente privado"..., o tengo que escribir mi propio constructor de copia para imitar esta función?

over 4 years ago · Santiago Trujillo
5 Respuestas
Responde la pregunta

0

Si lo entiendo correctamente, ¿quiere crear un nuevo objeto MyRecord con algunas de las propiedades de un objeto MyRecord existente?

Creo que algo en este sentido debería funcionar:

 MyRecord myRecord = ...; var changedRecord = new MyRecord with { AnyProp = myRecord.AnyProp... };
over 4 years ago · Santiago Trujillo Denunciar

0

Como puede ver con la descompilación de sharplab.io, la llamada with se traduce en una llamada al método <Clone>$() que llama internamente al constructor de copia generado por el compilador, por lo que debe definir su propio constructor de copia para evitar que se llame a Hash .

También como dice el documento with la palabra clave:

Si necesita personalizar la semántica de copia de registro, declare explícitamente un constructor de copia con el comportamiento deseado.

over 4 years ago · Santiago Trujillo Denunciar

0

Creo que el único mecanismo incorporado para permitir esto es el "constructor de copias". Como se documenta en esta publicación :

Un registro define implícitamente un "constructor de copia" protegido: un constructor que toma un objeto de registro existente y lo copia campo por campo en el nuevo...

El "constructor de copia" es solo un constructor que recibe una instancia del mismo tipo de registro como argumento. Si solo implementa este constructor, puede anular el comportamiento predeterminado de la expresión with . Hice una prueba basada en su código, aquí está la declaración de registro:

 public record MyRecord { protected MyRecord(MyRecord original) { ThisAndMayMoreComplicatedProperties = original.ThisAndMayMoreComplicatedProperties; hash = null; } public int ThisAndMayMoreComplicatedProperties { get; init; } string? hash = null; public string Hash { get { if (hash is null) { Console.WriteLine("The stored hash is currently null."); } return hash ??= ComputeHash(); } } string ComputeHash() => "".PadLeft(100, 'A'); }

Tenga en cuenta que cuando llamo al captador de propiedades compruebo si el hash es nulo e imprimo un mensaje. Luego hice un pequeño programa para verificar:

 var record = new MyRecord { ThisAndMayMoreComplicatedProperties = 100 }; Console.WriteLine($"{record.Hash}"); var newRecord = record with { ThisAndMayMoreComplicatedProperties = 200 }; Console.WriteLine($"{newRecord.Hash}");

Si ejecuta esto, notará que ambas llamadas a Hash imprimirán el mensaje de que el hash privado es nulo. Si comenta el constructor de copias, verá que solo la primera llamada imprime el valor nulo.

Así que creo que esto resuelve tu problema. La desventaja de este método es que tiene que copiar manualmente todas las propiedades de su registro, lo que puede ser bastante molesto. Si su registro tiene muchas propiedades, puede usar Reflection para iterar sobre ellas y copiar solo las que desee. También puede definir un Attribute personalizado para marcar campos ignorados. Pero tenga en cuenta que el uso de Reflection siempre tiene una sobrecarga de procesamiento.

over 4 years ago · Santiago Trujillo Denunciar

0

Encontré una solución para mi problema. Esto no resuelve el problema general y tiene otra desventaja: tengo que almacenar en caché el último estado del objeto, hasta que se vuelva a calcular el hash. Entiendo que esto es una compensación entre un cálculo potencialmente pesado y un mayor uso de memoria.

El truco consiste en recordar la última referencia de objeto cuando se calculó el hash. Cuando vuelvo a llamar a la propiedad Hash , compruebo si mientras tanto se ha cambiado la referencia del objeto (es decir, si se ha creado un nuevo objeto).

 public string Hash { get { if (hash == null || false == ReferenceEquals(this, hashRef)) { hash = ComputeHash(); hashRef = this; } return hash; } } private string? hash = null; private MyRecord? hashRef = null;

Todavía estoy buscando una mejor solución.

EDITAR: ¡Recomiendo la solución de Heinzi !

over 4 years ago · Santiago Trujillo Denunciar

0

Encontré una solución alternativa: puede (ab)usar la herencia para dividir el constructor de copias en dos partes: una manual solo para hash (en la clase base) y una generada automáticamente en la clase derivada copiando todos sus campos de datos valiosos.

Esto tiene la ventaja adicional de abstraer su lógica hash (no) de almacenamiento en caché. Aquí hay un ejemplo mínimo ( fiddle ):

 abstract record HashableRecord { protected string hash; protected abstract string CalculateHash(); public string Hash { get { if (hash == null) { hash = CalculateHash(); // do expensive stuff here Console.WriteLine($"Calculating hash {hash}"); } return hash; } } // Empty copy constructor, because we explicitly *don't* want // to copy hash. public HashableRecord(HashableRecord other) { } } record Data : HashableRecord { public string Value1 { get; init; } public string Value2 { get; init; } protected override string CalculateHash() => hash = Value1 + Value2; // do expensive stuff here } public static void Main() { var a = new Data { Value1 = "A", Value2 = "A" }; // outputs: // Calculating hash AA // AA Console.WriteLine(a.Hash); var b = a with { Value2 = "B" }; // outputs: // AA // Calculating hash AB // AB Console.WriteLine(a.Hash); Console.WriteLine(b.Hash); }
over 4 years ago · Santiago Trujillo Denunciar
Responde la pregunta
Encuentra empleos remotos

¡Descubre la nueva forma de encontrar empleo!

Top de empleos
Top categorías de empleo
Empresas
Publicar vacante Precios Comercial
Legal
Términos y condiciones Política de privacidad
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomiéndame algunas ofertas
Necesito ayuda