Remplacer le constructeur par défaut de la classe partielle par une autre classe partielle

Je ne pense pas que ce soit possible, mais si c’est le cas, j’en ai besoin 🙂

J’ai un fichier proxy généré automatiquement à partir de l’outil de ligne de commande wsdl.exe de Visual Studio 2008.

La sortie proxy est des classes partielles. Je veux remplacer le constructeur par défaut généré. Je préfère ne pas modifier le code car il est généré automatiquement.

J’ai essayé de créer une autre classe partielle et de redéfinir le constructeur par défaut, mais cela ne fonctionne pas. J’ai ensuite essayé d’utiliser le remplacement et les nouveaux mots-clés, mais cela ne fonctionne pas.

Je sais que je pourrais hériter de la classe partielle, mais cela signifierait que je devrais changer tout notre code source pour pointer vers la nouvelle classe parente. Je préférerais ne pas avoir à faire cela.

Des idées, des solutions de contournement ou des piratages?

//Auto-generated class namespace MyNamespace { public partial class MyWebService : System.Web.Services.Protocols.SoapHttpClientProtocol { public MyWebService() { ssortingng mySsortingng = "auto-generated constructor"; //other code... } } } //Manually created class in order to override the default constructor namespace MyNamespace { public partial class MyWebService : System.Web.Services.Protocols.SoapHttpClientProtocol { public override MyWebService() { //this doesn't work ssortingng mySsortingng = "overridden constructor"; //other code... } } } 

Ce n’est pas possible. Les classes partielles sont essentiellement des parties de la même classe; aucune méthode ne peut être définie deux fois ou remplacée, et cela inclut le constructeur.

Vous pouvez appeler une méthode dans le constructeur et l’implémenter uniquement dans l’autre fichier de pièce.

J’ai eu un prolem similaire, avec mon code généré créé par un fichier dbml (j’utilise des classes Linq-to-SQL).

Dans la classe générée, il appelle un vide partiel appelé OnCreated () à la fin du constructeur.

En bref, si vous voulez conserver les éléments importants du constructeur que la classe générée fait pour vous (ce que vous devriez probablement faire), créez dans votre classe partielle ce qui suit:

 partial void OnCreated() { // Do the extra stuff here; } 

Hmmm, je pense qu’une solution élégante serait la suivante:

 //* AutogenCls.cs file //* Let say the file is auto-generated ==> it will be overridden each time when //* auto-generation will be sortingggered. //* //* Auto-generated class, let say via xsd.exe //* partial class AutogenCls { public AutogenCls(...) { } } //* AutogenCls_Cunstomization.cs file //* The file keeps customization code completely separated from //* auto-generated AutogenCls.cs file. //* partial class AutogenCls { //* The following line ensures execution at the construction time MyCustomization m_MyCustomizationInstance = new MyCustomization (); //* The following inner&private implementation class implements customization. class MyCustomization { MyCustomization () { //* IMPLEMENT HERE WHATEVER YOU WANT TO EXECUTE DURING CONSTRUCTION TIME } } } 

Cette approche présente certains inconvénients (comme tout):

  1. Il n’est pas clair quand exactement sera exécuté le constructeur de la classe interne MyCustomization pendant toute la procédure de construction de la classe AutogenCls.

  2. S’il est nécessaire d’implémenter l’interface IDiposable pour que la classe MyCustomization gère correctement l’élimination des ressources non managées de la classe MyCustomization, je ne sais pas (encore) comment déclencher la méthode MyCustomization.Dispose () sans toucher au fichier AutogenCls.cs … (mais comme je l’ai dit “encore” 🙂

Mais cette approche offre une grande séparation par rapport au code généré automatiquement – toute la personnalisation est séparée dans un fichier de code src différent.

prendre plaisir 🙂

En fait, c’est maintenant possible, maintenant que des méthodes partielles ont été ajoutées. Voici le doc:

http://msdn.microsoft.com/en-us/library/wa80x488.aspx

Fondamentalement, l’idée est que vous pouvez déclarer et appeler une méthode dans un fichier où vous définissez la classe partielle, mais ne définissez pas réellement la méthode dans ce fichier. Dans l’autre fichier, vous pouvez ensuite définir la méthode. Si vous construisez un assembly où la méthode n’est pas définie, l’ORM supprimera tous les appels à la fonction.

Donc, dans le cas ci-dessus, cela ressemblerait à ceci:

// Classe générée automatiquement

 namespace MyNamespace { public partial class MyWebService : System.Web.Services.Protocols.SoapHttpClientProtocol { public MyWebService() { ssortingng mySsortingng = "auto-generated constructor"; OtherCode(); } } } partial void OtherCode(); 

// Classe créée manuellement pour remplacer le constructeur par défaut

 partial void OtherCode() { //do whatever extra stuff you wanted. } 

Il est quelque peu limité, et dans ce cas particulier, où vous avez un fichier généré que vous devez modifier, il peut ne pas être la bonne solution, mais pour ceux qui ont trébuché sur cette tentative de remplacer les fonctionnalités dans les classes partielles, cela peut être très utile.

Le problème rencontré par l’OP est que le proxy de référence Web ne génère aucune méthode partielle que vous pouvez utiliser pour intercepter le constructeur.

J’ai rencontré le même problème et je ne peux pas simplement passer à WCF car le service Web que je cible ne le prend pas en charge.

Je ne voulais pas modifier manuellement le code généré automatiquement car il deviendrait aplati si quelqu’un invoquait la génération de code.

J’ai abordé le problème sous un angle différent. Je savais que mon initialisation devait être faite avant une requête, il n’était pas vraiment nécessaire de le faire au moment de la construction, donc j’ai simplement remplacé la méthode GetWebRequest comme ça.

 protected override WebRequest GetWebRequest(Uri uri) { //only perform the initialization once if (!hasBeenInitialized) { Initialize(); } return base.GetWebRequest(uri); } bool hasBeenInitialized = false; private void Initialize() { //do your initialization here... hasBeenInitialized = true; } 

C’est une solution intéressante car elle n’implique pas le piratage du code généré automatiquement et correspond au cas d’utilisation exact de l’OP pour effectuer une connexion d’initialisation pour un proxy généré automatiquement par SoapHttpClientProtocol.

Vous ne pouvez pas faire ça. Je suggère d’utiliser une méthode partielle pour laquelle vous pouvez ensuite créer une définition. Quelque chose comme:

 public partial class MyClass{ public MyClass(){ ... normal construction goes here ... AfterCreated(); } public partial void OnCreated(); } 

Le rest devrait être assez explicite.

MODIFIER:

Je tiens également à souligner que vous devriez définir une interface pour ce service, à laquelle vous pouvez ensuite programmer, afin de ne pas avoir à vous référer à l’implémentation réelle. Si vous avez fait cela, vous auriez quelques autres options.

Je pense que vous pourriez être capable de faire cela avec PostSharp , et il semble que quelqu’un ait fait exactement ce que vous voulez pour les méthodes dans les classes partielles générées . Je ne sais pas si cela se traduira facilement par la possibilité d’écrire une méthode et si son corps remplace le constructeur car je ne lui ai pas encore donné le coup, mais cela semble valoir le coup.

Edit: c’est dans le même sens et semble également intéressant.

C’est à mon avis un défaut de conception dans la langue. Ils auraient dû autoriser plusieurs implémentations d’une méthode partielle, ce qui aurait fourni une solution intéressante. De manière encore plus agréable, le constructeur (également une méthode) peut également être simplement marqué de façon partielle et plusieurs constructeurs ayant la même signature s’exécuteront lors de la création d’un object.

La solution la plus simple consiste probablement à append une méthode partielle “constructeur” par classe partielle supplémentaire:

 public partial class MyClass{ public MyClass(){ ... normal construction goes here ... OnCreated1(); OnCreated2(); ... } public partial void OnCreated1(); public partial void OnCreated2(); } 

Si vous voulez que les classes partielles soient indépendantes les unes des autres, vous pouvez utiliser la reflection:

 // In MyClassMyAspect1.cs public partial class MyClass{ public void MyClass_MyAspect2(){ ... normal construction goes here ... } } // In MyClassMyAspect2.cs public partial class MyClass{ public void MyClass_MyAspect1(){ ... normal construction goes here ... } } // In MyClassConstructor.cs public partial class MyClass : IDisposable { public MyClass(){ GetType().GetMethods().Where(x => x.Name.StartsWith("MyClass")) .ForEach(x => x.Invoke(null)); } public void Dispose() { GetType().GetMethods().Where(x => x.Name.StartsWith("DisposeMyClass")) .ForEach(x => x.Invoke(null)); } } 

Mais en réalité, ils devraient simplement append des constructions de langage supplémentaires pour travailler avec des classes partielles.

Rien que je puisse penser. Le “meilleur” moyen que je puisse trouver est d’append un moteur avec un paramètre factice et de l’utiliser:

 public partial class MyWebService : System.Web.Services.Protocols.SoapHttpClientProtocol { public override MyWebService(int dummy) { ssortingng mySsortingng = "overridden constructor"; //other code... } } MyWebService mws = new MyWebService(0); 

Pour un proxy de service Web généré par Visual Studio, vous ne pouvez pas append votre propre constructeur dans la classe partielle (vous pouvez le faire, mais cela ne sera pas appelé). Au lieu de cela, vous pouvez utiliser l’atsortingbut [OnDeserialized] (ou [OnDeserializing]) pour connecter votre propre code au moment où la classe de proxy Web est instanciée.

 using System.Runtime.Serialization; partial class MyWebService { [OnDeserialized] public void OnDeserialized(StreamingContext context) { // your code here } } 

Parfois, vous n’avez pas access ou il n’est pas autorisé à modifier le constructeur par défaut. Pour cette raison, vous ne pouvez pas avoir le constructeur par défaut pour appeler des méthodes.

Dans ce cas, vous pouvez créer un autre constructeur avec un paramètre factice, et faire en sorte que ce nouveau constructeur appelle le constructeur par défaut en utilisant “: this ()”

 public SomeClass(int x) : this() { //Your extra initialization here } 

Et lorsque vous créez une nouvelle instance de cette classe, vous passez simplement un paramètre factice comme celui-ci:

 SomeClass objSomeClass = new SomeClass(0);