2010-11-12 11 views
18

Si defino una clase con un constructor privado predeterminado y un constructor público que tiene parámetros, ¿cómo puedo acceder al constructor privado?Acceso a un constructor privado desde fuera de la clase en C#

public class Bob 
{ 
    public String Surname { get; set; } 

    private Bob() 
    { } 

    public Bob(string surname) 
    { 
     Surname = surname; 
    } 
} 

puedo tener acceso al constructor privado a través de un método estático de la clase de la siguiente manera:

public static Bob GetBob() 
{ 
    return new Bob(); 
} 

pensé que podía acceder al constructor privado a través de un método de extensión, ya que (según mi entendimiento) los métodos de extensión se traducen de manera que parecen ser métodos estáticos en la clase, pero no puedo:

static class Fred 
{ 
    public static Bob Bobby(this Bob bob) 
    { 
     return new Bob(); 
    } 
} 

Entonces, ¿cómo puedo acceder al constructor privado?

Gracias


EDIT:

La razón por la que quería hacer esto era que quería crear pruebas para una de nuestras clases de negocios, pero no permitir que un consumidor de esta clase de ser capaz de instanciar un objeto incorrectamente. Lo estoy probando, así que sé (¡espero!) En qué circunstancias las pruebas fallarán. Todavía soy un n00b de prueba en este momento, así que mi idea puede o no haber sido la "manera incorrecta" de hacer las cosas.

He cambiado mi estrategia de prueba para hacer las cosas como lo haría un consumidor de esta clase, es decir, llamar a los métodos públicos y si los métodos públicos son correctos, suponiendo que los métodos privados son correctos. Todavía preferiría probar los métodos privados, pero mi jefe es respirando por mi cuello en un entregable :-(

+8

Por qué la estrecha votación? Sigue siendo una pregunta válida, incluso si no se recomienda obtener el constructor. – jgauffin

+0

De acuerdo, sigue siendo una pregunta válida, ¿por qué cerrar? –

+0

Re: Probando métodos privados. He descubierto que probando métodos privados de forma individual, mis pruebas son más pequeñas y más precisas que si solo pruebo métodos públicos. Tiendo a hacer 'privado' en 'protegido' y escribir una clase contenedora específica en la biblioteca de prueba para exponerlos como versiones públicas en lugar de utilizar el reflejo. –

Respuesta

37

Los constructores por defecto son privados por una razón. El desarrollador no lo hace privado por diversión.

Pero si aún desea usar el constructor predeterminado, lo obtiene mediante el uso de la reflexión.

var constructor = typeof(Bob).GetConstructor(BindingFlags.NonPublic|BindingFlags.Instance, null, new Type[0], null); 
var instance = (Bob)constructor.Invoke(null); 

Editar

vi su comentario acerca de las pruebas. Nunca pruebe métodos/propiedades protegidos o privados. Probablemente hayas hecho algo mal si no logras probar esos métodos/propiedades a través de la API pública. Eliminarlos o refactorizar la clase.

Editar 2

Olvidaste una bandera de unión.

+1

¿No es esto una especie de truco? ¿Omitir el motivo por el cual el constructor es privado? –

+6

Sí lo es. Es por eso que escribí * Los constructores por defecto son privados por una razón. El desarrollador no lo hace privado por diversión. * – jgauffin

+1

Gracias. Sin embargo, el método 'GetConstructor' devuelve null, por lo que el código arroja una NullReferenceException. 'typeof (Bob) .GetConstructors (BindingFlags.NonPublic);' devuelve una matriz vacía. – AndrewJacksonZA

0

El método Bobby todavía está en una clase diferente, llamada Fred. Es por eso que no se puede acceda al constructor prive de la clase Bob. Lo que está intentando hacer no es posible con los métodos adjuntos. Incluso si pueden adjuntarse en otra clase, se declaran fuera de esa clase y siguen las reglas de alcance/acceso habituales.

+0

Gracias por su aporte. Incluí 'Bobby' para mostrar lo que hice para que nadie pierda el tiempo sugiriendo métodos de extensión. – AndrewJacksonZA

0

Puede crear instancias de ese tipo mediante reflexión.

2

Hay varias formas de evitar este problema:

Una: hacer que el público constructor. Si necesita acceder desde fuera de la clase, ¿por qué es privado? (Es posible que solo desee acceder al constructor privado para la prueba, en cuyo caso se trata de un problema válido).

Dos: Hacer el constructor protegido, luego acceder a ella a través de una clase derivada:

public class Bob 
{ 
    public String Surname { get; set; } 

    protected Bob() 
    { } 

    public Bob(string surname) 
    { 
     Surname = surname; 
    } 
} 

public class Fred : Bob 
{ 
    public Fred() 
     : base() 
    { 
    } 
} 

Tres: Uso de reflexión (como se muestra por jgauffin).

+0

Como puede ver en la edición de la pregunta, es para probar, gracias. Y el formato todavía está fuera. – AndrewJacksonZA

+1

el código formateando errores cuando se usan listas en la misma respuesta. – jgauffin

+0

Saludos. Trataré de recordar eso para el futuro. –

1

En adicional a la respuesta de @ jgauffin que le dice cómo llamar a constructores privados a través de la reflexión:

¿Es posible cambiar los modificadores del constructor privado?

Parece que está implementando Factory Pattern en su código. Por lo tanto, se supone que el modificador es internal.

public class Product 
{ 
    //others can't create instances outside the namespace 
    internal Product() { }  
} 
public class ProductProvider 
{ 
    //they can only get standardized products by the provider 
    //while you have full control to Product class inside ProductProvider 
    public static CreateProduct() 
    { 
     //can create an instance here because they are in the same namespace 
     Product p = new Product();  
     //standardize the product 
     return p; 
    } 
} 

Los métodos de extensión

public static MyExt 
{ 
    public static void DoSomething(this Product p) { } 
} 

Calling p.DoSomething() realidad es igual a MyExt.DoSomething(p). No está poniendo este método en el producto de la clase.

+0

Solo una nota: el modificador de acceso "interno" no es una restricción en el nivel de espacio de nombres sino en el nivel de ensamblaje. ver: https: //msdn.microsoft.com/en-us/library/7c5ka91b.aspx. También podría simplemente poner el método de fábrica estático en la clase de Producto en sí. – RhysC

0
public class demo 
{ 
    private demo() 
    { 
     Console.WriteLine("This is no parameter private constructor"); 
    } 
    public demo(int a) 
    { 
     demo d = new demo('c');// u can call both private contstructors from here 
     demo dd = new demo(); 
     Console.WriteLine("This is one parameter public constructor"); 
    } 
    private demo(char a) 
    { 
     Console.WriteLine("This is one parameter public constructor::" + a); 
    } 
} 

class Program 
{ 
    static void Main(string[] args) 
    { 
     demo obj = new demo(7); 
     // demo obj = new demo(); // it will raise error 
     Console.ReadLine(); 
    } 
} 
+0

Comenta tu solución –

0

Si está utilizando núcleo dotnet se puede hacer lo siguiente sin ni siquiera tener que jugar con cualquier reflexión:

YourCustomObject player = (YourCustomObject)Activator.CreateInstance(typeof(YourCustomObject),true); 
Cuestiones relacionadas