2008-09-22 8 views
73

El punto de corrección const es poder proporcionar una vista de una instancia que no puede ser alterada o eliminada por el usuario. El compilador lo admite señalando cuándo se rompe la constness desde dentro de una función const, o intenta usar una función no const de un objeto const. Entonces, sin copiar el enfoque const, ¿hay alguna metodología que pueda usar en C# que tenga los mismos fines?"const correctness" en C#

Soy consciente de la inmutabilidad, pero eso realmente no se traslada a los objetos del contenedor, por poner un ejemplo.

+0

Hay una buena discusión acerca de posibles diseños de sólo lectura en [http://blogs.msdn.com/brada/archive/2004/02/04/67859.aspx](http://blogs.msdn. com/brada/archive/2004/02/04/67859.aspx) –

+0

Entonces, ¿qué hay de implementar 'const_cast' en C#? – kerem

Respuesta

57

me he encontrado con este problema muchas veces demasiado y terminó usando interfaces.

Creo que es importante descartar la idea de que C# sea de alguna forma, o incluso una evolución de C++. Son dos idiomas diferentes que comparten casi la misma sintaxis.

por lo general Expreso 'corrección const' en C# mediante la definición de una vista de sólo lectura de una clase:

public interface IReadOnlyCustomer 
{ 
    String Name { get; } 
    int Age { get; } 
} 

public class Customer : IReadOnlyCustomer 
{ 
    private string m_name; 
    private int m_age; 

    public string Name 
    { 
     get { return m_name; } 
     set { m_name = value; } 
    } 

    public int Age 
    { 
     get { return m_age; } 
     set { m_age = value; } 
    } 
} 
+3

Esta no es una de esas preguntas que tiene una "respuesta" como tal, pero realmente me gusta esta solución. Es elegante, puede adaptarse a muchas situaciones y es rápido para escribir. – tenpn

+11

Claro, pero ¿qué ocurre si uno de sus campos es una lista o un tipo rico? Su solución se complica muy rápido. –

+0

Devolver una colección interna se considera una mala práctica. O bien devuelve una interfaz de solo lectura para administrar esa lista particular de solo lectura o una copia de la lista original para que no se produzcan daños. – Trap

4

C# no tiene esta característica. Puede pasar argumentos por valor o por referencia. La referencia en sí es inmutable a menos que especifique el modificador ref. Pero los datos a los que se hace referencia no son inmutables. Por lo tanto, debe tener cuidado si desea evitar los efectos secundarios.

MSDN:

Passing Parameters

+0

Bueno, supongo que de eso se trata la pregunta: ¿cuál es la mejor manera de evitar los efectos secundarios de no tener una estructura constante? – tenpn

+0

Lamentablemente, solo los tipos inmutables pueden ayudarlo. Puede echar un vistazo a SpeC# - hay algunas comprobaciones de tiempo de compilación interesantes. – aku

27

para obtener el beneficio de la const-locura (o pureza en términos de programación funcional), tendrá que diseñar sus clases de una manera por lo que son inmutables, al igual que el La clase de cadena de C# es

Este enfoque es mucho mejor que simplemente marcar un objeto como de solo lectura, ya que con las clases inmutables puede pasar datos fácilmente en entornos de tareas múltiples.

+7

pero la inmutabilidad en realidad no se escala a objetos complejos, ¿o sí? – tenpn

+8

Argumentaría que si tu objeto fuera tan complejo que la inmutabilidad fuera imposible, tendrías un buen candidato para refactorizar. –

+2

Creo que este es el mejor del grupo. Los objetos inmutables se utilizan con poca frecuencia. – Will

2
  • El const palabra clave puede utilizarse para constantes de tiempo de compilación como tipos primitivos y cadenas
  • El de sólo lectura palabra clave puede utilizarse para las constantes de tiempo de ejecución, tales como los tipos de referencia

El problema con readonly es que solo permite que la referencia (puntero) sea constante. La cosa a la que se hace referencia (apuntada) aún se puede modificar. Esta es la parte difícil, pero no hay forma de evitarla. Implementar objetos constantes significa hacer que no expongan ningún método o propiedad mutable, pero esto es incómodo.

Ver también Effective C#: 50 Specific Ways to Improve Your C# (Tema 2 - Prefiero sólo lectura a const.)

3

interfaces son la respuesta, y en realidad son más poderosos que "const" en C++. const es una solución única para el problema donde "const" se define como "no establece miembros o llama a algo que establece miembros". Esa es una buena forma abreviada de const-ness en muchos escenarios, pero no en todos. Por ejemplo, considere una función que calcula un valor basado en algunos miembros pero también almacena en caché los resultados. En C++, eso se considera no const, aunque desde la perspectiva del usuario es esencialmente const.

Las interfaces le dan más flexibilidad para definir el subconjunto específico de capacidades que desea proporcionar de su clase.¿Quieres const-ness? Solo proporcione una interfaz sin métodos de mutación. ¿Quieres permitir configurar algunas cosas pero no otras? Proporcione una interfaz con solo esos métodos.

+14

No es 100% correcto. Los métodos C++ const pueden mutar los miembros marcados como 'mutable'. – Constantin

+3

Lo suficiente como para crear const-ness. los diseñadores de C++ se dieron cuenta de que una talla única para todos es una talla única para todos. – munificent

+8

La ventaja de C++ es que tiene const para la mayoría de los casos, y Puedes implementar interfaces para otros. Ahora, además de const, C++ tiene la palabra clave mutable para aplicar a los atributos como cachés de datos, o mecanismos de bloqueo (mutexes o similares). Const no 'no cambiará ningún atributo interno) sino que no cambiará el estado del objeto como se percibe desde el exterior. Es decir, cualquier uso del objeto antes y después de llamar a un método const arrojará el mismo resultado. –

23

Solo quiero señalar para usted que muchos de los contenedores de System.Collections.Generics tienen un método AsReadOnly que le devolverá una colección inmutable.

3

Acuerde con algunos de los otros ver el uso de los campos de solo lectura que inicializa en el constructor, para crear objetos inmutables.

public class Customer 
    { 
    private readonly string m_name; 
    private readonly int m_age; 

    public Customer(string name, int age) 
    { 
     m_name = name; 
     m_age = age; 
    } 

    public string Name 
    { 
     get { return m_name; } 
    } 

    public int Age 
    { 
     get { return m_age; } 
    } 
    } 

Como alternativa también se puede añadir alcance de acceso en las propiedades, es decir, conseguir pública y protegida conjunto?

public class Customer 
    { 
    private string m_name; 
    private int m_age; 

    protected Customer() 
    {} 

    public Customer(string name, int age) 
    { 
     m_name = name; 
     m_age = age; 
    } 

    public string Name 
    { 
     get { return m_name; } 
     protected set { m_name = value; } 
    } 

    public int Age 
    { 
     get { return m_age; } 
     protected set { m_age = value; } 
    } 
    } 
+3

Estos son enfoques diferentes que realmente no se ajustan a todo el problema. Con el nivel de control de acceso solo permite derivar clases de los cambios, en muchos casos esto no modelará el mundo real de manera apropiada. Un maestro no se deriva de un registro de un alumno, pero puede querer cambiar las calificaciones del alumno, aunque el alumno no puede cambiar las calificaciones, pero puede leerlas ... solo para nombrar un ejemplo simple. –