web-dev-qa-db-fra.com

Comment puis-je alias un nom de classe en C #, sans avoir à ajouter une ligne de code à chaque fichier qui utilise la classe?

je veux créer un alias pour un nom de classe. La syntaxe suivante serait parfaite:

public class LongClassNameOrOneThatContainsVersionsOrDomainSpecificName
{
   ...
}

public class MyName = LongClassNameOrOneThatContainsVersionOrDomainSpecificName;

mais il ne compilera pas.


Exemple

Remarque Cet exemple est fourni uniquement pour la convenance. N'essayez pas de résoudre ce problème particulier en suggérant de modifier la conception de l'ensemble du système. La présence ou l'absence de cet exemple ne change pas la question d'origine.

Certains codes existants dépendent de la présence d'une classe statique:

public static class ColorScheme
{
   ...
}

Ce jeu de couleurs est le jeu de couleurs Outlook 2003. je veux introduire un jeu de couleurs Outlook 2007, tout en conservant le jeu de couleurs Outlook 2003:

public static class Outlook2003ColorScheme
{
   ...
}

public static class Outlook2007ColorScheme
{
   ...
}

Mais je suis toujours confronté au fait que le code dépend de la présence d'une classe statique appelée ColorScheme. Ma première pensée a été de créer une classe ColorScheme que je descendrai d'Outlook2003 ou d'Outlook2007:

public static class ColorScheme : Outlook2007ColorScheme
{
}

mais vous ne pouvez pas descendre d'une classe statique.

Ma prochaine pensée a été de créer la classe ColorScheme statique, mais de rendre les classes Outlook2003ColorScheme et Outlook2007ColorScheme non statiques. Ensuite, une variable statique dans la classe ColorScheme statique peut pointer vers l'un ou l'autre "vrai" jeu de couleurs:

public static class ColorScheme
{
    private static CustomColorScheme = new Outlook2007ColorScheme();
    ...
}

private class CustomColorScheme 
{ 
   ...
}

private class Outlook2008ColorScheme : CustomColorScheme 
{
    ...
}

private class Outlook2003ColorScheme : CustomColorScheme 
{
   ...
}

mais cela nécessiterait que je convertisse une classe composée entièrement de couleurs statiques en lecture seule en propriétés redéfinissables, puis ma classe ColorScheme devrait avoir les 30 getters de propriété différents thunk down dans l'objet contenu.

C'est tout simplement trop de frappe.

Donc, ma prochaine pensée était d'alias la classe:

public static ColorScheme = Outlook2007ColorScheme;

Mais cela ne compile pas.

Comment puis-je alias une classe statique dans un autre nom?


Mise à jour: Quelqu'un peut-il s'il vous plaît ajouter la réponse "Vous ne pouvez pas faire cela en C #" , donc je peux le marquer comme accepté répondre. Quiconque souhaite obtenir la réponse à la même question trouvera cette question, la réponse acceptée et un certain nombre de solutions de contournement qui pourraient être utiles ou non.

je veux juste terminer cette question.

69
Ian Boyd

Vous ne pouvez pas alias un nom de classe en C #.

Il y a des choses que vous pouvez faire sans aliaser un nom de classe en C #.

Mais pour répondre à la question d'origine: vous ne pouvez pas alias un nom de classe en C #.


pdate: Les gens ne savent pas pourquoi using ne fonctionne pas. Exemple:

Form1.cs

private void button1_Click(object sender, EventArgs e)
{
   this.BackColor = ColorScheme.ApplyColorScheme(this.BackColor);
}

ColorScheme.cs

class ColorScheme
{
    public static Color ApplyColorScheme(Color c) { ... }
}

Et tout fonctionne. Maintenant, je veux créer une nouvelle classe , et alias ColorScheme (afin que aucun code ne doive être modifié):

ColorScheme.cs

using ColorScheme = Outlook2007ColorScheme;

class Outlook2007ColorScheme
{
    public static Color ApplyColorScheme(Color c) { ... }
}

Ohh, je suis désolé. Ce code ne compile pas:

enter image description here

Ma question était de savoir comment alias une classe en C #. Cela ne peut pas être fait. Il y a des choses que je peux faire qui sont pas alias un nom de classe en C #:

  • remplacez tous ceux qui dépendent de ColorScheme par usingColorScheme à la place (solution de contournement de changement de code car je ne peux pas alias)
  • changer tout le monde qui dépend de ColorScheme pour utiliser un modèle d'usine leur une classe ou une interface polymorphe (solution de contournement de changement de code car je ne peux pas alias)

Mais ces solutions de contournement impliquent de casser le code existant: pas une option.

Si les gens dépendent de la présence d'une classe ColorScheme, je dois réellement copier/coller une classe ColorScheme.

En d'autres termes: je ne peux pas alias un nom de classe en C #.

Cela contraste avec d'autres langages orientés objet, où je pourrais définir l'alias:

ColorScheme = Outlook2007ColorScheme

et j'aurais fini.

11
Ian Boyd

Si vous modifiez le nom de classe d'origine, vous pouvez réécrire le code dépendant en utilisant un alias d'importation comme substitut typedef:

using ColorScheme = The.Fully.Qualified.Namespace.Outlook2007ColorScheme;

Cela doit aller en haut du fichier/espace de noms, tout comme les usings ordinaires.

Je ne sais pas si c'est pratique dans votre cas, cependant.

110
Konrad Rudolph

Vous pouvez créer un alias pour votre classe en ajoutant cette ligne de code:

using Outlook2007ColorScheme = YourNameSpace.ColorScheme;
21
mohammedn

Vous voulez un ( Factory | Singleton ), selon vos besoins. La prémisse est de faire en sorte que le code client n'ait pas à savoir quel schéma de couleurs il obtient. Si la palette de couleurs doit être étendue à l'application, un singleton devrait convenir. Si vous pouvez utiliser un schéma différent dans différentes circonstances, un modèle Factory est probablement le chemin à parcourir. Quoi qu'il en soit, lorsque le jeu de couleurs doit changer, le code ne doit être modifié qu'à un seul endroit.

public interface ColorScheme {
    Color TitleBar { get; }
    Color Background{ get; }
    ...
}

public static class ColorSchemeFactory {

    private static ColorScheme scheme = new Outlook2007ColorScheme();

    public static ColorScheme GetColorScheme() { //Add applicable arguments
        return scheme;
    }
}

public class Outlook2003ColorScheme: ColorScheme {
   public Color TitleBar {
       get { return Color.LightBlue; }
   }

    public Color Background {
        get { return Color.Gray; }
    }
}

public class Outlook2007ColorScheme: ColorScheme {
   public Color TitleBar {
       get { return Color.Blue; }
   }

    public Color Background {
        get { return Color.White; }
    }
}
12

essaye ça:

using ColorScheme=[fully qualified].Outlook2007ColorScheme
10
dpurrington

Aliaser la façon dont vous souhaitez le faire ne fonctionnera pas en C #. Cela est dû au fait que l'aliasing est effectué via la directive using, qui est limitée au fichier/espace de noms en question. Si vous avez 50 fichiers qui utilisent l'ancien nom de classe, cela signifie 50 emplacements à mettre à jour.

Cela dit, je pense qu'il existe une solution simple pour rendre votre changement de code aussi minimal que possible. Faites de la classe ColorScheme une façade pour vos appels aux classes réelles avec l'implémentation, et utilisez le using dans ce fichier pour déterminer quelle ColorScheme vous utilisez.

En d'autres termes, procédez comme suit:

using CurrentColorScheme = Outlook2007ColorScheme;
public static class ColorScheme
{
   public static Color ApplyColorScheme(Color c)
   {
       return CurrentColorScheme.ApplyColorScheme(c);
   }
   public static Something DoSomethingElse(Param a, Param b)
   {
       return CurrentColorScheme.DoSomethingElse(a, b);
   }
}

Ensuite, dans votre code derrière, ne changez rien:

private void button1_Click(object sender, EventArgs e)
{
   this.BackColor = ColorScheme.ApplyColorScheme(this.BackColor);
}

Vous pouvez ensuite mettre à jour les valeurs de ColorScheme en mettant à jour une ligne de code (using CurrentColorScheme = Outlook2008ColorScheme;).

Quelques préoccupations ici:

  • Chaque nouvelle méthode ou définition de propriété devra alors être ajoutée à deux endroits, à la classe ColorScheme et à la Outlook2007ColorScheme classe. C'est un travail supplémentaire, mais s'il s'agit d'un vrai code hérité, cela ne devrait pas être fréquent. En prime, le code dans ColorScheme est si simple que tout bug possible est très évident.
  • Cette utilisation des classes statiques ne me semble pas naturelle; J'essaierais probablement de refactoriser le code hérité pour le faire différemment, mais je comprends aussi que votre situation peut ne pas le permettre.
  • Si vous avez déjà une classe ColorScheme que vous remplacez, cette approche et toute autre peuvent poser problème. Je vous conseille de renommer cette classe en quelque chose comme ColorSchemeOld, puis d'y accéder via using CurrentColorScheme = ColorSchemeOld;.
4
Timothy

J'ajoute ce commentaire aux utilisateurs qui trouvent cela longtemps après qu'OP ait accepté leur "réponse". L'aliasing en C # fonctionne en spécifiant le nom de classe en utilisant son espace de noms complet. Une fois défini, le nom d'alias peut être utilisé dans sa portée. Exemple.

using aliasClass = Fully.Qualified.Namespace.Example;
//Example being the class in the Fully.Qualified.Namespace

public class Test{

  public void Test_Function(){

    aliasClass.DoStuff();
    //aliasClass here representing the Example class thus aliasing
    //aliasClass will be in scope for all code in my Test.cs file
  }

}

Toutes mes excuses pour le code rapidement saisi, mais j'espère que cela explique comment cela doit être implémenté afin que les utilisateurs ne se trompent pas en pensant que cela ne peut pas être fait en C #.

4
J-Americano

Je suppose que vous pouvez toujours hériter de la classe de base sans rien ajouter

public class Child : MyReallyReallyLongNamedClass {}

[~ # ~] mise à jour [~ # ~]

Mais si vous avez la possibilité de refactoriser le class lui-même: Un nom de classe est généralement inutilement long en raison du manque de namespaces.

Si vous voyez des cas comme ApiLoginUser, DataBaseUser, WebPortalLoginUser, cela indique généralement un manque de namespace en raison de la crainte que le nom User pourrait entrer en conflit.

Dans ce cas cependant, vous pouvez utiliser l'alias namespace, comme cela a été souligné dans les articles ci-dessus

using LoginApi = MyCompany.Api.Login;
using AuthDB = MyCompany.DataBase.Auth;
using ViewModels = MyCompany.BananasPortal.Models;

// ...
AuthDB.User dbUser;
using ( var ctxt = new AuthDB.AuthContext() )
{
    dbUser = ctxt.Users.Find(userId);
}

var apiUser = new LoginApi.Models.User {
        Username = dbUser.EmailAddess,
        Password = "*****"
    };

LoginApi.UserSession apiUserSession = await LoginApi.Login(apiUser);
var vm = new ViewModels.User(apiUserSession.User.Details);
return View(vm);

Notez que les noms class sont tous User, mais dans différents namespaces. Citant PEP-20: Zen of Python :

Les espaces de noms sont une excellente idée de klaxon - faisons-en plus!

J'espère que cela t'aides

3
percebus

Est-il possible de passer à l'utilisation d'une interface?

Peut-être pourriez-vous créer une interface IColorScheme que toutes les classes implémentent?

Cela fonctionnerait bien avec le modèle d'usine comme indiqué par Chris Marasti-Georg

2
chills42

C'est une réponse partielle très tardive - mais si vous définissez la même classe 'ColorScheme', dans le même espace de nom 'Outlook', mais dans des assemblys séparés, l'un appelé Outlook2003 et l'autre Outlook2007, alors tout ce que vous devez faire est de référencer l'assembly approprié .

0
Mark Farmiloe