¿Cuándo usar [Pure] en un constructor?

19

Estoy aprendiendo acerca de los contratos de código en .NET, y estoy tratando de entender la idea de constructores puros. La documentación de los contratos de código establece:

Todos los métodos que se llaman dentro de un contrato deben ser puros; es decir, no deben actualizar ningún estado preexistente. Un método puro puede modificar los objetos que se han creado después de ingresar al método puro.

Y la PureAttributedocumentación dice:

Indica que un tipo o método es puro, es decir, no realiza ningún cambio de estado visible.

Entiendo estas afirmaciones cuando se trata de métodos, pero ¿qué pasa con los constructores? Supongamos que tuvieras una clase como esta:

public class Foo
{
    public int Value { get; set; }

    public Foo(int value) {
        this.Value = value;
    }
}

Este constructor obviamente afecta el estado del nuevo Fooobjeto, pero no tiene otros efectos secundarios (por ejemplo, no manipula ninguno de los parámetros ni llama a métodos no puros). ¿Es este un candidato [Pure]o no? ¿Cuál es el significado de colocar un [Pure]atributo en un constructor, y cuándo debo hacer esto en mi propio código?

pswg
fuente

Respuestas:

14

Decoras un método con [Pure]:

  • Si el método no tiene efectos secundarios. Por ejemplo, si el método accede a una base de datos y la modifica o su resultado depende de la base de datos, no es puro.

  • Y si espera usarlo en contratos de código. Por ejemplo, si el método es puro , pero no tiene intención de usarlo en contratos de código, agregarlo [Pure]no tendría ningún beneficio y no hará que su código sea más rápido.

En lo que respecta a los constructores, parece que se supone que son puros en .NET y no necesitan un atributo explícito. Miré varios constructores en la fuente de .NET Framework, como DateTime, y no tienen [Pure]atributo.

Supongo que esto se hace por varias razones:

  • Puede ser demasiado poco práctico tener que escribir un constructor sin parámetros con [Pure]atributo solo para poder usar la clase / estructura en un contrato.

  • Algunos, como String, no tienen constructores explícitos.

  • Los constructores reciben un trato especial incluso fuera de los contratos de código; por ejemplo, no se espera que arrojes excepciones dentro de ellos .

  • [Pure]es solo una convención que está aquí para simplificar su vida, pero no existe una comprobación estática real para garantizar que el método decorado con este atributo sea puro. void DestroyDatabase()puede ser decorado como puro, y los contratos de código no notarán nada malo.

    Actualmente no hay ningún componente de los Contratos de Código que verifique si los métodos declarados puros son realmente puros. Por lo tanto, si un programador decora un método con [Puro], simplemente se cree.

    De los contratos de código # 5: pureza del método

  • .NET Framework en sí contiene constructores que no son puros. Por ejemplo, List<T>(IEnumerable<T> collection)es realmente impuro si recorrer la colección tiene efectos secundarios.

  • Los contratos deben ser simples. Puedo imaginar fácilmente un contrato como Contract.Requires(!string.IsNullOrEmpty(name)), por lo que hay buenas razones para declarar string.IsNullOrEmptypuro estático .

    Por otro lado, si necesita un StringBuilderpara construir la cadena, buscará algo llamando a un método de instancia de su clase de negocios, probablemente esté haciendo un mal uso de los contratos. Esa es también la razón por la StringBuilder.ToStringque no está marcado como puro, incluso si pudiera serlo (¿o sí?)

Arseni Mourzenko
fuente
El verificador de contratos asume muchos contratos de código en tipos de sistema, incluido " cualquier método cuyo nombre completo comience con" System.Diagnostics.Contracts.Contract "," System.String "," System.IO.Path "o" System .Type " ". Desafortunadamente, no estoy seguro si mirar los tipos .NET es demasiado útil cuando se trata de contratos de código.
pswg 01 de
3
La pureza es una de esas cosas donde todo el código llamado también tiene que ser puro, o la persona que llama no es "pura". Me resulta difícil creer que todos los constructores se consideren puros por defecto.
Frank Hileman 01 de
@FrankHileman: yo también. No tengo un compilador de C # en este momento, pero sería suficiente escribir una clase con un constructor y sin [Pure]atributo, y usarlo en otro lugar en un contrato para tener una respuesta definitiva.
Arseni Mourzenko 01 de
1

El objeto no se puede usar hasta que se construya en este caso. Por lo tanto, el constructor es puro. Si el constructor llamó a otro código, o invocó a un delegado, y el otro código modificó la propiedad mutable, no sería puro. Para estar más seguro, es mejor hacer que la propiedad sea inmutable.

Frank Hileman
fuente
Entonces, ¿un constructor puro es un método puro que puede cambiar el estado de la clase actual, siempre y cuando satisfaga las otras condiciones de ser puro? Por cierto, la propiedad es mutable porque quería enfatizar que esta clase en sí misma no es pura.
pswg 01 de
@pswg: Usted creó una pregunta interesante que probablemente debe ser respondida por Microsoft. Suponga que el constructor invocó un método que modificó la propiedad mutable; ¿el constructor seguiría siendo puro? Creo que técnicamente no lo sería, a pesar de que la modificación es "invisible" para los espectadores externos. Como no hay otro código invocado en su ejemplo original, debe ser puro por cualquier definición que se me ocurra.
Frank Hileman 01 de
@pswg: Excepto que el conjunto de propiedades también es una llamada al método. Creo que debería preguntar en los foros de MSDN.
Frank Hileman 01 de
Supongo que si la idea central de la pureza es si el método realiza o no cambios observables , entonces, en ese sentido, independientemente de si llama o no a métodos no puros, siempre y cuando los llamantes no puedan observar los cambios , seguiría siendo un método puro.
pswg 01 de
@pswg: Esa es la definición abstracta. Pero si escribiera un analizador para estas cosas, probablemente también se consideraría una llamada a un método no puro para que la persona que llama no sea pura. Solo por simplicidad de implementación. Entonces la pregunta es, ¿es un constructor una llamada de método normal o qué tan profundo es el análisis?
Frank Hileman