2010-12-06 22 views
11

¿Cómo llamar al constructor protegido?¿Cómo llamar al constructor protegido en C#?

public class Foo{ 
    public Foo(a lot of arguments){} 
    protected Foo(){} 
} 
var foo=??? 

Esto, obviamente, no supera la prueba:

public class FooMock:Foo{} 
var foo=new FooMock(); 
Assert(typeof(Foo), foo.GetType()); 

Respuesta

21

Sólo puede llamar a que a partir de una subclase, básicamente. Su clase FooMock ya estará llamando al constructor protegido, porque es equivalente a:

public class FooMock : Foo 
{ 
    public FooMock() : base() // Call the protected base constructor 
    { 
    } 
} 

Sin embargo, su afirmación fallará debido a que el tipo de objeto que se refiere a ser foo es FooMock, no Foo.

Una afirmación del formulario foo is Foopasará a.

No puede construir una instancia de solo Foo llamando directamente al constructor protegido. El objetivo de estar protegido en lugar de público es asegurarse de que solo lo llamen las subclases (o dentro del texto de Foo).

Es posible que pueda llamarlo con reflejo dentro de un contexto de plena confianza, pero le insto a que no lo haga.

+0

"pero me gustaría que no insto para hacerlo "¿por qué no? Lo necesito para la prueba. tal vez eso tenga sentido, después de todo? –

+1

@Arnis L .: En ese punto, estás haciendo poco más que inventar un truco para hacer una prueba, que es tan útil como no escribir la prueba. Este es un buen momento para dar un paso atrás y echar un vistazo a _por qué_ este constructor está 'protegido', ya que implica que el comportamiento que busca (y está probando) está explícitamente no respaldado (y, por lo tanto, no se puede probar). – David

+1

@Arnis: por lo general, si necesita eludir el modelo de accesibilidad con reflejo, eso sugiere que no debe tratar de obtener acceso al miembro en cuestión, o debe aumentar la accesibilidad usted mismo. –

2

La única forma de llamar a un constructor protegido es derivar de la clase y tener el delegado de la clase derivada en él o tener un método estático para crearlo u otro método interno.

EDITAR: ¡Lo que dijo Skeet!

+5

+1 por EDITAR: ¡Lo que dijo Skeet! – Aliostad

1

No puede llamar al método protected, aunque puede llamar al internal (usando el atributo InternalsVisibleTo). Debes exponerlo de una manera diferente.

0

Si necesita llamar explícitamente al constructor de la clase base que en la subclase, usted tiene que utilizar la palabra clave base

20

sin parámetros de llamada protegida/constructor privado: no

Foo foo = (Foo)Activator.CreateInstance(typeof(Foo), true); 

Call constructor público con parámetros:

var foo = (Foo)typeof(Foo) 
    .GetConstructor(
     BindingFlags.NonPublic | BindingFlags.CreateInstance | BindingFlags.Instance, 
     null, 
     new[] { typeof(double) }, 
     null 
    ) 
    .Invoke(new object[] { 1.0 }); 

    class Foo 
    { 
    private Foo(double x){...} 
    } 
+0

Esta debería ser la respuesta aceptada. –

0

Serj-Tm respondió adecuadamente pero Activator puede hacerlo también:

var foo = (Foo) Activator.CreateInstance(typeof(Foo), 
       BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance, 
       null, 
       new object[] { 2.0 }, 
       CultureInfo.InvariantCulture); 
1

Si se quiere evitar el costo reflexión repetida, puede utilizar expresiones. Aquí hay un ejemplo de llamar a un constructor privado con un valor de cadena.

private static Func<string, T> CreateInstanceFunc() 
    { 
     var flags = BindingFlags.NonPublic | BindingFlags.Instance; 
     var ctor = typeof(T).GetConstructors(flags).Single(
      ctors => 
      { 
       var parameters = ctors.GetParameters(); 
       return parameters.Length == 1 && parameters[0].ParameterType == typeof(string); 
      }); 
     var value = Expression.Parameter(typeof(string), "value"); 
     var body = Expression.New(ctor, value); 
     var lambda = Expression.Lambda<Func<string, T>>(body, value); 

     return lambda.Compile(); 
    } 

Ahorre el costo de compilar la función varias veces guardándola en un campo estático.

private static readonly Lazy<Func<string, T>> CreateInstance = new Lazy<Func<string, T>>(CreateInstanceFunc); 

Ahora se puede crear el objeto con

CreateInstance.Value("Hello") 
0

puede ser que esto ayudará a:

abstracta clase padre:

public abstract class Animal 
    { 

     private string name; 

     public Animal(string name) 
     { 

      this.Name = name; 
     } 

     public Animal() { } 
     public string Name 
     { 

      get { return this.name; } 

      set { this.name = value; } 

     } 

     public virtual void talk() 
     { 

      Console.WriteLine("Hi,I am an animal"); 

     } 


    } 

clase con el constructor protegido:

public class Lion : Animal 
    { 
     private string yahoo; 

     protected Lion(string name) : base(name) 
     { 

      this.Yahoo = "Yahoo!!!"; 
     } 

     public string Yahoo 
     { 
      get 
      { 
       return yahoo; 
      } 

      set 
      { 
       yahoo = value; 
      } 
     } 

     public Lion() { } 
    } 

clase derivada de la clase Kiara Lion:

public class Kiara : Lion 
    { 

     public Kiara(string name) : base(name) 
     { 

     } 

     public override void talk() 
     { 

      Console.WriteLine("HRRRR I'm a Kiara"); 

     } 

     public Kiara() { } 

    } 

clase derivada de la clase Simba Lion:

public class Simba : Lion 
    { 

     public Simba(string name) : base(name) 
     { 

     } 

     public override void talk() 
     { 

      Console.WriteLine("HRRRR I'm a {0} and this is my daughter:{1} {2}", 
      new Simba("Simba").Name, 
      new Kiara("Kiara").Name, 
      new Simba("Simba").Yahoo); 
     } 


     public Simba() { } 

    } 

aplicación de la función principal:

 public static void Main(string[] args) 
     { 


      Animal lion = new Simba(); 
      lion.Name = "Simba"; 
      lion.talk(); 
      Animal lion1 = new Kiara(); 
      lion1.Name = "Kiara"; 
      lion1.talk(); 
     } 
Cuestiones relacionadas