2011-05-17 17 views
16

Así que tengo una clase base que tiene muchos hijos. Esta clase base define algunas propiedades de solo lectura y variables que tienen valores predeterminados. Estos pueden ser diferentes, dependiendo del niño.¿Asignar un valor a un campo readonly heredado?

Las propiedades/campos de solo lectura le permiten cambiar el valor de la variable dentro del constructor y también la definición, pero en ningún otro lado. Obtengo un error de 'la variable de solo lectura se puede asignar en un constructor' si trato de cambiar el valor de una variable readonly heredada en el constructor de la clase secundaria. ¿Por qué es esto y cómo puedo evitar esto, sin Reflexión?

Mi intención: Permitir la extensibilidad del usuario a través de scripts donde solo pueden cambiar ciertos campos una vez.

+0

Tuve un problema muy similar, y obtuve una [respuesta] (http://stackoverflow.com/questions/42682527/eliminate-duplicate-c-sharp-property-bodies) que le permite realizar una única asignación a un miembro. Funcionalmente de solo lectura, y todo el código repetitivo está en una sola ubicación. – wizard07KSU

Respuesta

6

Adam tiene la respuesta correcta. Si le preocupa el espacio que ocupará (¿número de parámetros en el constructor?), Entonces debe abordar eso como un problema diferente con una solución diferente: crear una clase BaseConfig, que contenga todas esas propiedades y eso es todo lo que necesita ser transferido. Base puede entonces asignar todos sus campos de solo lectura desde las propiedades de BaseConfig, o en su lugar puede tener Base mantener solo un campo de solo lectura de tipo BaseConfig y referirse a eso para los valores.

En cuanto a por qué esto es así, vea C# constructor execution order con respecto a cuándo se inicializarán/inicializarán los campos readonly de cada clase.

+0

Esto me entristece un poco; Esperaba una forma realmente agradable de implementar esto, por lo que hacer scripts para mi motor sería realmente ingenioso e inteligente. Oh bien. Una clase BaseConfig funcionará igual de bien, ¡gracias! –

17

El motivo es que solo se puede asignar a readonly campos en el constructor de esa clase.
Según the definition of readonly in the C# Reference (énfasis mío):

Cuando una declaración de campo incluye un modificador de sólo lectura, las asignaciones a los campos introducidos por la declaración sólo puede ocurrir como parte de la declaración o en un constructor en la misma clase.

Para solucionar esto, puede hacer que un constructor protegido en la base tome un parámetro para la propiedad de solo lectura.

Un ejemplo:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 

namespace ConsoleApplication1 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      Base b = new Child(); 
      Console.WriteLine(b.i); 
      Console.Read(); 
     } 
    } 

    class Base 
    { 
     public readonly int i; 

     public Base() 
     { 
      i = 42; 
     } 

     protected Base(int newI) 
     { 
      i = newI; 
     } 
    } 

    class Child : Base 
    { 
     public Child() 
      : base(43) 
     {} 
    } 
} 
+3

El único inconveniente de esta solución es que no le permite calcular los valores que se pasarán a la clase base. – Kent

+1

@Kent: es posible llamando a un método estático en la lista de parámetros del constructor de la clase base. Ver http: // stackoverflow.com/questions/1651444/modifying-parameter-values-before-sending-to-base-constructor – ofthelit

0

esto es imposible por el diseño. intente pasar los valores a protected constructor de la clase base

6

Puede obtener el comportamiento exacto que está buscando mediante el uso de propiedades de solo obtener virtuales.

public class BSE 
{ 
    virtual public int Prop 
    { 
     get 
     { 
      return 6; 
     } 
    } 
} 
public class Derived : BSE 
{ 
    public override int Prop 
    { 
     get 
     { 
      return 10; 
     } 
    } 
} 

campos son fuera del lado de la herencia y el modelo de sobrecarga y no deben utilizarse para proporcionar características polimórficas.

+0

Esto suena más parecido; pero todavía es un salto bastante grande del limpio 'público readonly int number = 5'. –

+0

@Ruirize ¿Está asignando una constante a un campo de solo lectura? Eso realmente suena como un abuso de los campos de solo lectura y que es posible que desee utilizar propiedades virtuales en su lugar. – CodesInChaos

3

Puede usar la propiedad con acceso público get y accessor de conjunto protegido. Las clases derivadas pueden establecer el valor de esta propiedad.

+0

Un ejemplo ayudaría aquí ... –

Cuestiones relacionadas