2009-03-15 15 views
8

¿Hay alguna manera de acceder al campo de respaldo de una propiedad para hacer la validación, cambiar el seguimiento, etc.?Acceso al campo de respaldo en una propiedad de automóvil

¿Es posible algo como esto? Si no, ¿hay algún plan para tenerlo en .NET 4/C# 4?

public string Name 
{ 
    get; 
    set 
    { 
     if (value != <Keyword>) 
     { 
      RaiseEvent(); 
     } 
     <Keyword> = value; 
    } 
} 

El principal problema que tengo es que el uso de las propiedades de auto no permite la misma flexibilidad en la validación, etc., que una propiedad con un campo respaldo explícito hace. Sin embargo, un campo de respaldo explícito tiene la desventaja en algunas situaciones de permitir que la clase en la que está contenido acceda al campo de respaldo cuando debe acceder y reutilizar la validación, cambio de seguimiento, etc. de la propiedad al igual que cualquier otra clase que pueda acceder la propiedad externamente

En el ejemplo anterior el acceso al campo respaldo podría estar en el ámbito de la propiedad evitando así que se eluda la validación de la propiedad, el control de cambios, etc.

Editar: he cambiado < Copia de campo> a < palabra clave >. Propondría una nueva palabra clave similar al valor. campo haría bien aunque estoy seguro de que se está utilizando en una gran cantidad de código existente.

Respuesta

3

Después de leer sus comentarios en la respuesta de Mehrdad, creo que entiendo su problema un poco mejor.

Parece que le preocupa la capacidad del desarrollador para acceder a un estado privado en la clase que están escribiendo, omitiendo su lógica de validación, etc. Esto sugiere que el estado no debe estar incluido en la clase.

Sugeriría la siguiente estrategia. Escribe una clase genérica que represente ValidatedValue. Esta clase solo tiene el valor de respaldo y solo permite el acceso/mutación a través de los métodos get y set. Un delegado se pasa a la ValidatedValue para representar la lógica de validación:

public class ValidatedValue<T> 
{ 
    private T m_val; 
    public ValidationFn m_validationFn; 

    public delegate bool ValidationFn(T fn); 

    public ValidatedValue(ValidationFn validationFn) 
    { 
     m_validationFn = validationFn; 
    } 

    public T get() 
    { 
     return m_val; 
    } 

    public void set(T v) 
    { 
     if (m_validationFn(v)) 
     { 
      m_val = v; 
     } 
    } 
} 

Se podría, por supuesto, añadir más delegados según sea necesario (por ejemplo, para apoyar la notificación de cambio de pre/post).

Su clase ahora usaría ValidatedValue en lugar de una tienda de respaldo para su propiedad.

El ejemplo siguiente muestra una clase, MyClass, con un número entero validado en menos de 100. Tenga en cuenta que la lógica para lanzar una excepción está en MyClass, no en ValidatedValue. Esto le permite hacer reglas de validación complejas que dependen de otro estado contenido en MyClass. La notación Lambda se usó para construir el delegado de validación; en cambio, podría haberse vinculado a una función de miembro.

public partial class MyClass 
{ 
    private ValidatedValue<int> m_foo; 

    public MyClass() 
    { 
     m_foo = new ValidatedValue<int>(
      v => 
      { 
       if (v >= 100) RaiseError(); 
       return true; 
      } 
     ); 
    } 

    private void RaiseError() 
    { 
     // Put your logic here.... 
     throw new NotImplementedException(); 
    } 

    public int Foo 
    { 
     get { return m_foo.get(); } 
     set { m_foo.set(value); } 
    } 
} 

Espero que ayude - algo fuera del tema original, pero creo que está más en línea con sus preocupaciones reales. Lo que hemos hecho es quitar la lógica de validación de la propiedad y ponerla en los datos, que es exactamente donde la deseabas.

+0

Es una buena solución pero una gran cantidad de código para acceder al campo de la misma manera que accedemos al nuevo valor en un setter con la palabra clave value ser mucho más conciso y elegante. –

+2

Probablemente pueda hacer que la sintaxis sea más agradable agregando operator = y coersion a T en la clase ValidatedValue. Básicamente, usted quiere que se comporte como ValidatedValue es una T. –

1

Si lo va a hacer, ¿por qué está utilizando propiedades de automóviles?

Una propiedad simple lo ha hecho en 1.0. No creo que tenga sentido agregar complejidad al lenguaje para cada caso especial. O necesita la propiedad para hacer un modelo de tienda/recuperación simple o necesita más que eso. En este último caso, una propiedad normal servirá.

+0

El beneficio de las propiedades de automóviles es que se ven obligados a utilizar la propiedad en lugar del campo de apoyo de métodos dentro de la clase. –

+0

No veo ningún beneficio al forzar a una clase a no usar lo que declara. Es por eso que no tenemos menos de modificadores de acceso 'privados'. –

+0

Lo sé, pero en algunos casos el campo es meramente de almacenamiento. No hay otra razón para declararlo y desea poder controlar cómo se accede a ese almacenamiento sin importar dónde se encuentre. –

13

No, no hay. Si desea acceder al campo de respaldo, entonces no use las propiedades automáticas y haga las suyas propias.

Estoy de acuerdo en que sería genial tener un campo que solo fuera accesible por la propiedad y no por el resto de la clase. Yo usaría eso todo el tiempo.

+0

Me gustaría exigir el uso de la propiedad dentro de la clase en la que se encuentra la propiedad. No deseo que el código de la clase acceda directamente al campo. –

+3

Las clases deben poder confiar en sí mismas para manejar adecuadamente sus propias partes privadas. –

+2

IMO esta es la respuesta a la pregunta * real *. La respuesta marcada como la respuesta es una respuesta a una pregunta tangencial separada:/ – Catskul

1

No se puede hacer esto, me temo. Esa es una de las razones por las que comencé a escribir MoXAML Power Toys, para proporcionar la capacidad de convertir propiedades automáticas en propiedades de notificación.

+0

Parece interesante.Todavía no resuelve el problema de tener un campo por el que no debería estar accesible, excepto desde el alcance de la propiedad. –

6

Como los MSDN estados:

"en C# 3.0 y posterior, propiedades implementadas automáticamente hacer de la propiedad-declaración más concisa cuando no se requiere lógica adicional en los descriptores de acceso También permiten. código de cliente para crear objetos Cuando declara una propiedad como que se muestra en el siguiente ejemplo, el compilador crea un campo de respaldo privado, anónimo al que solo se puede acceder a través de la propiedad get y set accesos ".

Dado que tiene una lógica adicional en sus accesorios, el uso de propiedades implementadas automáticamente no es apropiado en su escenario.

Si bien existe el campo de respaldo, se le da un nombre revuelto que le impida referencia a ella fácilmente - la idea es que nunca se referencia al campo directamente.Por cuestiones de interés, puede usar Reflector para desmontar su código y descubrir el nombre del campo, pero le recomendaría que no use el campo directamente ya que este nombre puede ser volátil, por lo que su código podría romperse en cualquier momento.

+0

Tenía la impresión de que el único motivo para el nombre destrozado era asegurarse de que fuera único. Sin embargo, no estoy seguro de cómo lo hace. Agrega caracteres extraños que no son válidos para un nombre de variable. –

+0

Lo que no entiendo es por qué el campo anónimo incluso necesita un nombre ... –

2

No, pero se puede en una subclase:

public class Base 
{ 
    public string Name 
    { 
     get; 
     virtual set; 
    } 
} 

public class Subclass : Base 
{ 
    // FIXME Unsure as to the exact syntax. 
    public string Name 
    { 
     override set 
     { 
      if (value != base.Name) 
      { 
       RaiseEvent(); 
      } 

      base.Name = value; 
     } 
    } 
} 
Cuestiones relacionadas