2010-09-26 10 views
63

Bajo qué condiciones se supone que debo hacer las llamadas al constructor :base() y :this() siguiendo los paréntesis de mi constructor (o incluso en otros lugares en el código). ¿Cuándo son estas llamadas buenas prácticas y cuándo son obligatorias?base() y this() mejores prácticas de constructores

+0

pena por la ambigüedad ... Sé lo que estas llamadas están haciendo. Simplemente no tenía claro el escenario cuando debería o tengo que hacer estas llamadas. Lugares donde si no los hago, o bien estoy condenado de inmediato o habrá un error latente o una calidad de código deficiente. Recientemente tuve tanto dolor de cabeza, por lo tanto, quería aclarar estos escenarios. - – explorer

Respuesta

85

: base(...)

Si se omite la llamada a un constructor base se llamará al constructor base predeterminada de forma automática.

Es obligatorio llamar a un constructor base explícitamente si no hay un constructor predeterminado.

Incluso si hay un constructor predeterminado, es posible que desee llamar a un constructor diferente del constructor predeterminado. En este caso, puede desear usar base(foo, bar) para llamar a un constructor diferente que el constructor base.

No considero una mala práctica omitir base() cuando desea llamar al constructor predeterminado de la clase base, aunque si desea ser explícito, no veo ningún daño al incluirlo. Es una cuestión de gusto.

: this(...)

Esta sintaxis le permite llamar a un constructor con una firma diferente a otro dentro de la misma clase. Nunca es obligatorio hacer esto, pero a veces puede ser útil.

Un ejemplo de cuándo puede ser útil es para reutilizar código común en los constructores. Por ejemplo, en C# 3.5 o antes es posible que desee simular parámetros opcionales en un constructor:

Foo(int x, int y) 
{ 
    this.x = x; 
    this.y = y; 
} 

Foo(int x) : this(x, 10) {} // y defaults to 10 

con C# 4.0 parámetros opcionales están disponibles ahora lo que reduce la necesidad de este enfoque.

Una forma alternativa de reutilizar el código en los constructores es factorizarlo en una función estática que se llama desde cada constructor que desea usarla.

5

Busque "encadenamiento de constructor en C#". Básicamente, se ve así:

MyClass():base() //default constructor calling superclass constructor 
{ 
} 

MyClass(int arg):this() //non-basic constructor calling base constructor 
{ 
    //extra initialization 
} 

Ayuda a eliminar la duplicación de código en los constructores - les dividió en partes básicas y específicas.

+0

Gracias. "Constructor encadenando" era el término que no podía recordar. – JNappi

4

Utilice: base() cuando desee que el constructor de la clase base se llame automáticamente como primera instrucción de su constructor. : this() es similar, pero llama a otro constructor en la misma clase.

En base :() y esto(): puede pasar como parámetros valores constantes, o expresión basada en los parámetros de su constructor.

Es obligatorio llamar al constructor base cuando la clase base no tiene un constructor predeterminado (uno que no toma ningún parámetro). No sé de un caso en el que: esto() es obligatorio.

public class ABaseClass 
{ 
    public ABaseClass(string s) {} 
} 

public class Foo : AChildClass 
{ 
    public AChildClass(string s) : base(s) {} //base mandatory 
    public AChildClass() : base("default value") {} //base mandatory 
    public AChildClass(string s,int i) : base(s+i) {} //base mandatory 
} 

public class AnotherBaseClass 
{ 
    public ABaseClass(string s) {} 
    public ABaseClass():this("default value") {} //call constructor above 
} 

public class Foo : AnotherChildClass 
{ 
    public AnotherChildClass(string s) : base(s) {} //base optional 

} 
28

En primer lugar, cuando son obligatorios.

Cuando una clase Derived se deriva de una clase Base, y Base no tiene un constructor por defecto (sin parámetros), Derived debe llamar base() explícitamente con parámetros.

public class Base { 
    public Base(int i) { } 
} 


public class Derived : Base { 
    // public Derived() { } wouldn't work - what should be given for i? 
    public Derived() : base(7) { } 
    public Derived(int i) : base(i) { } 
} 

Cuando es una buena práctica? Siempre que quieras llamar a un constructor diferente.

Supongamos que agrega, en mi ejemplo anterior, contenido a los constructores en Derivado.

public class Derived : Base { 
    // public Derived() { } wouldn't work - what should be given for i? 
    public Derived() : base(7) { 
     Console.WriteLine("The value is " + 7); 
    } 
    public Derived(int i) : base(i) { 
     Console.WriteLine("The value is " + i); 
    } 
} 

¿Usted nota la duplicación aquí? Es más simple llamar al constructor this().

public class Derived : Base { 
    // public Derived() { } wouldn't work - what should be given for i? 
    public Derived() : this(7) { } 
    public Derived(int i) : base(i) { 
     Console.WriteLine("The value is " + i); 
    } 
} 
+0

Entonces, el orden de llamada en el último ejemplo sería: 'base (7)', y luego 'Derived (7)', y luego 'Derived()'. En otras palabras, la parte 'this (7)' en sí NO activará 'base()' (suponiendo que haya un método base). ¿Es correcto? – RayLuo

+1

Correcto; los constructores siempre están encadenados, y cada clase llama a los constructores de su clase base. Usando 'this' puedes reutilizar el otro constructor de esta clase (que usará' base', ya sea implícitamente sin argumentos o explícitamente); usando 'base' puedes elegir qué constructor de la clase base llamar. – configurator

21

Uso base cuando hay herencia, y una clase padre ya proporciona la funcionalidad que usted está tratando de lograr.

Utilice this cuando desee hacer referencia a la entidad actual (o uno mismo), utilícela en el encabezado/firma del constructor cuando no desee duplicar la funcionalidad que ya está definida en otro constructor.

Básicamente, usando la base y esto en la cabecera de un constructor es mantener su código DRY, por lo que es más fácil de mantener y menos detallado

He aquí un ejemplo absolutamente sin sentido, pero creo que ilustra la idea de mostrar cómo los dos pueden ser usados.

class Person 
{ 
    public Person(string name) 
    { 
     Debug.WriteLine("My name is " + name); 
    } 
} 

class Employee : Person 
{ 
    public Employee(string name, string job) 
     : base(name) 
    { 
     Debug.WriteLine("I " + job + " for money."); 
    } 

    public Employee() : this("Jeff", "write code") 
    { 
     Debug.WriteLine("I like cake."); 
    } 
} 

Uso:

var foo = new Person("ANaimi"); 
// output: 
// My name is ANaimi 

var bar = new Employee("ANaimi", "cook food"); 
// output: 
// My name is ANaimi 
// I cook food for money. 

var baz = new Employee(); 
// output: 
// My name is Jeff 
// I write code for money. 
// I like cake.