Pregunta

¿Hay alguna forma de acceder al campo de respaldo de una propiedad para realizar la validación, el seguimiento de cambios, etc.?

¿Es posible algo como lo siguiente? 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 automáticas no permite la misma flexibilidad en la validación, etc., que una propiedad con un campo de respaldo explícito. 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 debería acceder y reutilizar la validación, el seguimiento de cambios, etc. de la propiedad al igual que cualquier otra clase que pueda estar accediendo la propiedad externamente.

En el ejemplo anterior, el acceso al campo de respaldo se limitaría a la propiedad, evitando así la elusión de la validación de propiedad, el seguimiento de cambios, etc.

Editar: he cambiado < Backing Field & Gt; a < Palabra clave & Gt ;. Propondría una nueva palabra clave similar al valor. campo funcionaría bien, aunque estoy seguro de que se está utilizando en una gran cantidad de código existente.

¿Fue útil?

Solución

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

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

Sugeriría la siguiente estrategia. Escriba una clase genérica que represente un ValidatedValue. Esta clase contiene solo el valor de respaldo y solo permite el acceso / mutación a través de los métodos get y set. Se pasa un delegado al 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;
        }
    }
}

Podría, por supuesto, agregar más delegados según sea necesario (por ejemplo, para admitir la notificación previa / posterior al cambio).

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

El siguiente ejemplo muestra una clase, MyClass, con un número entero validado para ser inferior a 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 utilizó para construir el delegado de validación; en su lugar, podría haber vinculado a una función 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 quería.

Otros consejos

No, no lo hay. Si desea acceder al campo de respaldo, no use las propiedades automáticas ni las suyas.

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

Como MSDN dice:

  

" En C # 3.0 y posterior, implementado automáticamente   propiedades hacen declaración de propiedad   más conciso cuando no hay lógica adicional   Se requiere en la propiedad los accesos.   También permiten crear código de cliente   objetos Cuando declaras una propiedad como   mostrado en el siguiente ejemplo, el   compilador crea un privado, anónimo   solo se puede acceder al campo de respaldo   a través de la propiedad get and set   accesorios. "

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

Si bien el campo de respaldo existe, se le asigna un nombre mutilado para evitar que haga referencia a él fácilmente; la idea es que nunca haga referencia al campo directamente . En aras de los intereses, puede usar Reflector para desarmar su código y descubrir el nombre del campo, pero le recomendaría que no lo use directamente ya que este nombre puede ser volátil, por lo que su código podría romperse en cualquier momento.

No, pero puedes 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;
        }
    }
}

Si vas a hacerlo, ¿por qué estás usando propiedades automáticas?

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

No puedes 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.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top