2010-12-14 11 views
5
class Program 
{ 
    static void Main(string[] args) 
    { 
     Foo.Calc("Foo"); 
    } 
} 

public abstract class Base 
{ 
    protected static Func<string, int> CalcFunction; 

    public static void Calc(string str) 
    { 
     Console.WriteLine(CalcFunction(str)); 
    } 
} 

public class Foo : Base 
{ 
    static Foo() 
    { 
     CalcFunction = s => { return s.Length; }; 
    } 
} 

Cuando intento llamar a Foo.Calc ("Foo"); Tengo la excepción "Referencia de objeto no establecida en una instancia de un objeto". porque no se llamó al constructor estático de Foo y CalcFunction es nulo. No quiero utilizar el método Init para la clase Foo y llamarlo antes de llamar a Calc().Constructores de la orden de llamada

¿Puedo cambiar el orden de los constructores de llamadas?

+1

La herencia de mezcla y los miembros estáticos parece extraña. Si 'Calc' y' CalcFunction' no fueran estáticos, entonces 'Foo' tendría un constructor de instancia regular, y' CalcFunction' se inicializaría antes de la llamada a 'Calc'. –

Respuesta

6

No - su código ha sido compilado en

Base.Calc("Foo"); 

... así Foo no se inicializa en absoluto.

Esto no es una cuestión de orden de constructores estáticos que se está ejecutando ... es que el constructor estático para Foo simplemente no se está ejecutando en absoluto.

Básicamente, debe cambiar su diseño. Usted podría forzar el constructor estático de Foo para ejecutar creando una instancia de Foo, pero eso es bastante desagradable ... su código no será claro de esa manera.

+1

¿No quieres decir 'Base.Calc'? –

+0

@Brian: Sí, oops :) –

+0

¿Podría explicar por qué Foo.Calc ("Foo"); se compilará en Base.Calc ("Foo")? – ukraine

2

C# garantiza que, antes de utilizar cualquier código en Base, se ejecuta el constructor estático para Base. No hay nada para garantizar que se ejecutará cualquier código en Foo. (Usted ha escrito una llamada a Foo.Calc, pero esto es realmente una llamada a Base.Calc.)

no hay una solución simple: usted podría introducir un método init explícita o aplanar la jerarquía de clases, o mover CalcFunction en Foo.

1

Parece que ha entendido mal el uso de palabras clave estáticas y abstractas. Tener una clase abstracta con solo miembros estáticos casi no tiene sentido. ¿Está seguro de que esto no está más cerca de lo que estaba intentando?

class Program 
{ 
    static void Main(string[] args) 
    { 
     var foo = new Foo() 
     foo.Calc("Foo"); 
    } 
} 

public abstract class Base 
{ 
    protected Func<string, int> CalcFunction; 

    public void Calc(string str) 
    { 
     Console.WriteLine(CalcFunction(str)); 
    } 
} 

public class Foo : Base 
{ 
    public Foo() 
    { 
     this.CalcFunction = s => { return s.Length; }; 
    } 
} 
+0

Mejor aún: haga que 'CalcFunction' sea privado y agregue un constructor:' Base protegida (Func calcFunction) ' –

Cuestiones relacionadas