Accéder à un constructeur privé depuis L'extérieur de la classe en C#

Si je définis une classe avec un constructeur privé par défaut et un constructeur public qui a des paramètres, Comment puis-je accéder au constructeur privé?

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

   private Bob()
   { }

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

Je peux accéder au constructeur privé via une méthode statique de la classe comme ceci:

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

J'ai pensé que je pouvais accéder au constructeur privé via une méthode d'extension, puisque (selon ma compréhension) les méthodes d'extension sont convertis afin qu'ils semblent être méthodes statiques de la classe, mais je ne peux pas:

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

Alors, comment puis-je accéder au constructeur privé?

Merci


Modifier:

La raison pour laquelle je voulais faire cela était que je voulais créer des tests pour l'une de nos classes métier, mais ne pas permettre à un consommateur de cette classe de pouvoir instancier un objet de manière incorrecte. Je le teste, donc je sais (j'espère! dans quelles circonstances les tests échouent. Je suis toujours un test n00b en ce moment donc mon idée peut ou peut ne pas avoir été la " mauvaise façon" de faire les choses.

J'ai changé ma stratégie de test pour faire les choses comme le ferait un consommateur de cette classe, c'est-à-dire appeler les méthodes publiques et si les méthodes publiques sont correctes, en supposant que les méthodes privées sont correctes. Je préférerais toujours tester les méthodes privées, mais mon patron est respirant dans mon cou sur un livrable :- (

21
demandé sur AndrewJacksonZA 2010-11-12 11:26:17

7 réponses

constructeurs par Défaut sont privés pour une raison. Le développeur ne le rend pas privé pour le plaisir.

Mais si vous voulez toujours utiliser le constructeur par défaut, vous l'obtenez en utilisant la réflexion.

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

Modifier

J'ai vu votre commentaire sur les tests. Ne testez jamais les méthodes / propriétés protégées ou privées. Vous avez probablement fait quelque chose de mal si vous ne parvenez pas à tester ces méthodes/propriétés via L'API publique. Supprimez-les ou refactorisez-les classe.

Modifier 2

Oublié un drapeau de liaison.

39
répondu jgauffin 2010-11-12 09:24:17

, Il existe plusieurs façons de contourner ce problème:

Un: Faire le constructeur public. Si vous devez y accéder depuis l'extérieur de la classe, pourquoi est-il privé (il se peut que vous souhaitiez seulement accéder au constructeur privé pour tester, auquel cas il s'agit d'un problème valide).

deux : protégez le constructeur, puis accédez-y via une classe dérivée:

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

    protected Bob()
    { }

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

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

Trois : Utilisez la réflexion (comme le montre jgauffin).

2
répondu Dr Herbie 2010-11-12 09:32:13

En plus de la réponse de @jgauffin qui indique comment appeler des constructeurs privés via la réflexion:

Est-il possible de changer les paramètres du constructeur privé?

Il semble que vous implémentez le modèle D'usine dans votre code. Ainsi, le modificateur est censé être internal.

public class Product
{
   //others can't create instances directly outside the assembly
   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 Product CreateProduct()
   {
       Product p = new Product();    
       //standardize the product
       return p;
   }  
}

Les méthodes d'Extension

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

Appeler p.DoSomething() équivaut en fait à MyExt.DoSomething(p). Il ne met pas cette méthode dans le produit de classe.

2
répondu Danny Chen 2018-08-28 03:13:08

Vous pouvez instancier des instances de ce type via la réflexion.

0
répondu Frederik Gheysels 2010-11-12 08:30:24

La méthode Bobby est toujours dans une classe différente, appelée Fred. C'est pourquoi vous ne pouvez pas accéder au constructeur prive de la classe Bob. Ce que vous essayez de faire n'est pas possible avec joint méthodes. Même s'ils peuvent être attachés à une autre classe, ils sont toujours déclarés en dehors de cette classe et suivent les règles habituelles de portée/accès.

0
répondu Liviu M. 2010-11-12 08:46:09

Si vous utilisez dotnet core, vous pouvez faire ce qui suit sans même avoir à jouer avec une réflexion:

YourCustomObject player = (YourCustomObject)Activator.CreateInstance(typeof(YourCustomObject),true);
0
répondu DenLilleMand 2017-01-22 17:16:21
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();
    }
}
-1
répondu G Ravi 2014-04-04 07:27:08