Come posso creare un alias di un nome di classe in C #, senza dover aggiungere una riga di codice a ogni file che utilizza la classe?


88

Voglio creare un alias per il nome di una classe. La seguente sintassi sarebbe perfetta:

public class LongClassNameOrOneThatContainsVersionsOrDomainSpecificName
{
   ...
}

public class MyName = LongClassNameOrOneThatContainsVersionOrDomainSpecificName;

ma non verrà compilato.


Esempio

Nota Questo esempio viene fornito solo per comodità. Non cercare di risolvere questo particolare problema suggerendo di modificare il design dell'intero sistema. La presenza o la mancanza di questo esempio non cambia la domanda originale.

Alcuni codici esistenti dipendono dalla presenza di una classe statica:

public static class ColorScheme
{
   ...
}

Questa combinazione di colori è la combinazione di colori di Outlook 2003. voglio introdurre una combinazione di colori di Outlook 2007, pur mantenendo la combinazione di colori di Outlook 2003:

public static class Outlook2003ColorScheme
{
   ...
}

public static class Outlook2007ColorScheme
{
   ...
}

Ma sono ancora di fronte al fatto che il codice dipende dalla presenza di una classe statica chiamata ColorScheme. Il mio primo pensiero è stato quello di creare una ColorSchemeclasse che erediterò da Outlook2003o da Outlook2007:

public static class ColorScheme : Outlook2007ColorScheme
{
}

ma non puoi ereditare da una classe statica.

Il mio pensiero successivo è stato quello di creare la ColorSchemeclasse statica , ma make Outlook2003ColorSchemee le Outlook2007ColorSchemeclassi non statiche. Quindi una variabile statica nella ColorSchemeclasse statica può puntare a uno schema di colori "vero":

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

private class CustomColorScheme 
{ 
   ...
}

private class Outlook2008ColorScheme : CustomColorScheme 
{
    ...
}

private class Outlook2003ColorScheme : CustomColorScheme 
{
   ...
}

ma ciò richiederebbe che io converta una classe composta interamente di colori statici di sola lettura in proprietà sovrascrivibili, e quindi la mia ColorSchemeclasse avrebbe bisogno di avere i 30 diversi getter di proprietà inseriti nell'oggetto contenuto.

È solo troppa digitazione.

Quindi il mio pensiero successivo è stato quello di creare un alias per la classe:

public static ColorScheme = Outlook2007ColorScheme;

Ma questo non si compila.

Come posso alias una classe statica in un altro nome?


Aggiornamento: qualcuno può aggiungere la risposta "Non puoi farlo in C #" , così posso contrassegnarla come risposta accettata. Chiunque altro desideri la risposta alla stessa domanda troverà questa domanda, la risposta accettata e una serie di soluzioni alternative che potrebbero o non potrebbero essere utili.

Voglio solo chiudere questa domanda.


potresti anche accettare la risposta di Chris, anche se non vuoi implementarla
devio

2
Non è la risposta, è una soluzione alternativa. La risposta è che non puoi, almeno fino a quando qualcuno non arriva e pubblica la sintassi effettiva per farlo.
Ian Boyd

1
Per chiunque venga qui, la risposta accettata non è corretta in quanto il commento con il punteggio più alto funziona perfettamente nei progetti VS 2010 e VS 2017 c # su cui sto lavorando. Lo spazio dei nomi completo deve essere utilizzato per specificare la classe durante la configurazione dell'alias, ma una volta impostato l'alias funziona all'interno dell'ambito definito.
J-Americano

Ho dovuto leggere la risposta di Ian e i suoi commenti in grande dettaglio prima di capire cosa stava cercando. Vuole dichiarare un alias di classe in un posto , piuttosto che doverlo aggiungere all'inizio di ogni file che fa riferimento alla classe. Non sono a conoscenza di linguaggi fortemente tipizzati che supportano questo. (Se qualcuno conosce un tale linguaggio, mi piacerebbe saperlo.) Ho modificato il titolo per renderlo più chiaro.
ToolmakerSteve

A proposito, per chiunque stia cercando di fare qualcosa di simile: se queste sono classi che stai definendo, l'approccio C # è definire un interface, che tutte le tue classi implementano. Come accennato nella risposta di chills42 . È quindi possibile definire un "servizio" o una "fabbrica" ​​che restituisce un oggetto che implementa tale interfaccia, a seconda delle circostanze attuali (ad esempio piattaforma / sistema operativo) o su un file di configurazione.
ToolmakerSteve

Risposte:


131

Non puoi . La prossima cosa migliore che puoi fare è avere usingdichiarazioni nei file che usano la classe.

Ad esempio, potresti riscrivere il codice dipendente utilizzando un alias di importazione (come quasi typedefsostituto):

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

Sfortunatamente questo deve entrare in ogni ambito / file che utilizza il nome.

Pertanto non so se questo sia pratico nel tuo caso.


9
Se potesse andare all'inizio del file che conteneva la classe originale: sarebbe fantastico. Ma usingdeve essere aggiunto a tutto il codice rotto. Inoltre nega il valore di avere un unico alias, che mi consente di cambiare tutti gli utenti della ColorSchemeclasse esistente in una nuova classe, senza modifiche. In altre parole: voglio creare un alias della ColorSchemeclasse con un'altra classe.
Ian Boyd

C'è un modo per ottenere lo stesso e propagare l'alias con l'ereditarietà. cioè tutte le classi che estendono MyClass potranno usare ColorScheme invece di.Fully.Qualified ... ColorScheme semplicemente aggiungendo l'istruzione using nel file sorgente di MyClass?
Florian Burel

Bene, è stato molto pratico per il mio caso. Infine C # smetterà di disegnare i percorsi dei miei file.
ElDoRado 1239

25

Puoi creare un alias per la tua classe aggiungendo questa riga di codice:

using Outlook2007ColorScheme = YourNameSpace.ColorScheme;

Il nome "ColorScheme" non esiste nel contesto attuale
Ian Boyd

7
hai bisogno di Fully.Qualified.Namespace.Of.ColorScheme
Jamie Pate

Pensavo che in C # si potessero solo alias spazi dei nomi (non classi) in questo modo, dove in VB.Net è possibile creare alias spazi dei nomi o classi utilizzando Imports. Ho sbagliato?
Nick

Non hai bisogno di un nome completo se metti la usingdirettiva nel suo spazio dei nomi, ad esempio quando hai bisogno di un alias della tua classe.
Elvedin Hamzagic

12

Vuoi un ( Factory | Singleton ), a seconda delle tue esigenze. La premessa è fare in modo che il codice client non debba sapere quale combinazione di colori sta ottenendo. Se la combinazione di colori dovrebbe essere ampia per l'applicazione, un singleton dovrebbe andare bene. Se puoi utilizzare uno schema diverso in circostanze diverse, un pattern Factory è probabilmente la strada da percorrere. In ogni caso, quando la combinazione di colori deve cambiare, il codice deve essere modificato solo in un punto.

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; }
    }
}

Sembra meno una fabbrica e più un debole tentativo di un pattern singleton. È più probabile che una fabbrica parametrizzi il metodo di creazione; avresti qualcosa di più simile a: public static ColorScheme GetColorScheme (string descriptor);
OwenP,

Vero: l'idea di base è assicurarsi che quando esce Office 2012, il codice deve cambiare solo in 1 posizione.
Chris Marasti-Georg,

1
Questo sicuramente funziona, ma certamente è una soluzione aziendale a un problema semplice.
Ian Boyd

11

Non è possibile alias un nome di classe in C #.

Ci sono cose che puoi fare che non sono alias di un nome di classe in C #.

Ma per rispondere alla domanda originale: non puoi alias un nome di classe in C #.


Aggiornamento: le persone sono confuse perché usingnon funziona. Esempio:

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) { ... }
}

E tutto funziona. Ora voglio creare una nuova classe e un alias ColorScheme (in modo che non sia necessario modificare il codice ):

ColorScheme.cs

using ColorScheme = Outlook2007ColorScheme;

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

Ohh, mi dispiace. Questo codice non viene compilato:

inserisci qui la descrizione dell'immagine

La mia domanda era come creare l' alias di una classe in C #. Non si può fare. Ci sono cose che posso fare che non sono alias di un nome di classe in C #:

  • cambia invece tutti quelli che dipendono ColorSchemeda using ColorScheme(soluzione alternativa al cambio di codice perché non posso creare l'alias)
  • cambia tutti coloro che dipendono ColorSchemeper utilizzare un modello di fabbrica, una classe o un'interfaccia polimorfica (soluzione alternativa alla modifica del codice perché non posso alias)

Ma queste soluzioni alternative comportano la violazione del codice esistente: non un'opzione.

Se le persone dipendono dalla presenza di una ColorSchemeclasse, devo effettivamente copiare / incollare una ColorSchemeclasse.

In altre parole: non posso creare l'alias di un nome di classe in C #.

Questo contrasta con altri linguaggi orientati agli oggetti, dove potrei definire l'alias:

ColorScheme = Outlook2007ColorScheme

e avrei finito.


22
È assolutamente possibile alias un nome di classe in C #. "using <alias_name> = <fully_qualified_name>;"
clemahieu

8
Come ha detto @clemahieu, puoi assolutamente alias un nome di classe, devi solo usare il nome completo. Inoltre, se si crea un alias per una classe generica, è possibile aggiungere il qualificatore di classe generico. Ad esempio: using ShortName = MyNamespace.SubNamespace.GenericClass <MyType>;
Dan Morphis

11
Voto negativo: hai dichiarato "Non è possibile alias un nome di classe in C #". Puoi. Quello che non puoi fare è alias una classe nel modo in cui vuoi - che è un requisito abbastanza giustificato, ma la tua affermazione non è corretta.
Tom W

8
Come hanno sottolineato diversi poster, dover utilizzare il nome qualificato non proibisce in alcun modo l'aliasing. È possibile alias la classe. Devi solo usare il nome completo per farlo. Potresti trovare questo inconveniente, ma non rende vera l'affermazione "Non puoi alias un nome di classe in C #". Forse il modo in cui funziona l'alias in C # è diverso da quello che ti aspettavi. Va bene, se è così, dichiaralo. Ma puoi creare un alias di un nome di classe in C # perché la specifica afferma che puoi farlo, in base alla definizione che fornisce.
Tom W

5
Mi piace come noi programmatori faremo le nostre dichiarazioni tra le righe. Quello che Ian sta realmente dicendo è che C # è stupido e rotto perché non può fare una semplice cosa di base che chiunque vorrebbe fare e dovrebbe essere in grado di fare. Ha ragione, indipendentemente dal fatto che una semantica specifica ti renda felice.
IQpierce

10

prova questo:

using ColorScheme=[fully qualified].Outlook2007ColorScheme

Il nome "ColorScheme" non esiste nel contesto attuale
Ian Boyd

2
hai bisogno di Fully.Qualified.Namespace.Of.ColorScheme
Jamie Pate

6

Aggiungo questo commento per gli utenti che lo trovano molto tempo dopo che OP ha accettato la loro "risposta". L'aliasing in C # funziona specificando il nome della classe usando il suo spazio dei nomi completo. Uno definito, il nome alias può essere utilizzato all'interno del suo ambito. Esempio.

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
  }

}

Mi scuso per il codice digitato rapidamente, ma si spera che spieghi come dovrebbe essere implementato in modo che gli utenti non siano indotti a credere che non possa essere fatto in C #.


Questo sarebbe ancora più chiaro se si ha mostrato la dichiarazione dell'altra classe: namespace Fully.Qualified.Namespace{ public class Example {... public void DoStuff(){... }... } }.
ToolmakerSteve

1
Per essere chiari, questo è diverso da quello che cerca Ian. Ian ha una situazione in cui non può (o non vuole) alterare i file sorgente che fanno riferimento a una classe. Vuole un modo per apportare una modifica in un solo punto della sua applicazione o libreria , risultando in quella che sembra essere una classe con il nome desiderato, che tutti gli altri codici possono usare [senza dover aggiungere l'istruzione "using" a più sorgenti file - ad esempio, quella fonte potrebbe non essere disponibile per la modifica].
ToolmakerSteve

4

L'aliasing nel modo in cui vorresti farlo non funzionerà in C #. Questo perché l'aliasing viene eseguito tramite la usingdirettiva, che è limitata al file / spazio dei nomi in questione. Se hai 50 file che usano il vecchio nome della classe, significa 50 posti da aggiornare.

Detto questo, penso che ci sia una soluzione semplice per rendere la modifica del codice il più minima possibile. Rendi la ColorSchemeclasse una facciata per le tue chiamate alle classi effettive con l'implementazione e usa usingin quel file per determinare quale ColorSchemeusare.

In altre parole, fai questo:

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);
   }
}

Quindi nel tuo codice dietro, non cambiare nulla:

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

È quindi possibile aggiornare i valori di ColorSchemeaggiornando una riga di codice ( using CurrentColorScheme = Outlook2008ColorScheme;).

Un paio di preoccupazioni qui:

  • Ogni nuovo metodo o definizione di proprietà dovrà quindi essere aggiunto in due punti, alla ColorSchemeclasse e alla Outlook2007ColorSchemeclasse. Questo è un lavoro extra, ma se questo è vero codice legacy, non dovrebbe essere un evento frequente. Come bonus, il codice inColorScheme è così semplice che ogni possibile bug è molto evidente.
  • Questo uso di classi statiche non mi sembra naturale; Probabilmente proverei a rifattorizzare il codice legacy per farlo in modo diverso, ma capisco anche che la tua situazione potrebbe non consentirlo.
  • Se hai già una ColorSchemeclasse che stai sostituendo, questo approccio e qualsiasi altro potrebbero essere un problema. Ti consiglio di rinominare quella classe in qualcosa di simile ColorSchemeOlde quindi di accedervi tramite using CurrentColorScheme = ColorSchemeOld;.

3

Suppongo che tu possa sempre ereditare dalla classe base senza aggiungere nulla

public class Child : MyReallyReallyLongNamedClass {}

AGGIORNARE

Ma se hai la capacità di refactoring di classse stesso: un nome di classe di solito è inutilmente lungo a causa della mancanza di namespaces.

Se vedi casi come ApiLoginUser, DataBaseUser, WebPortalLoginUser, è di solito l'indicazione di mancanza di namespacecausa il timore che il nome Userdi conflitto potrebbe.

In questo caso, tuttavia, puoi usare l' namespacealias , come è stato sottolineato nei post precedenti

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);

Nota come i classnomi sono tutti User, ma in diversi namespaces. Citando PEP-20: Zen of Python :

Gli spazi dei nomi sono una grande idea clamorosa: facciamo di più di quelli!

Spero che sia di aiuto


2
sempre, a meno che tu non possa: es. lezione sigillata
mikus

ma in molti casi non funzionerà. es. public class MyList: List {} - se successivamente provi MyList xyz = something.ToList (); rimarrai bloccato.
Offler

@Offler Potresti (e probabilmente dovresti) ricorrere a una newparola chiave per tali metodi o persino inventare i tuoi ExtensionMethods, giusto? In ogni caso è mia ferma opinione che dovresti sempre usare le classi Collection vanilla (cioè Dictionary, List, IEnumerable, IQueryable, ecc.) Con Models / ViewModels / POCO personalizzati. Come afferma
Mvc

@percebus non funziona in tutti i casi. Cerco di trasformare il codice vintage in cui le parti utilizzano un'API non più supportata in una nuova. il codice di trasformazione durign verrà modificato da altri e dovrebbe essere ancora eseguibile, quindi entrambi dovrebbero essere utilizzabili solo ora. convergere cose oltre 700.000 LOC (senza commenti) e lasciarlo comunque eseguibile sarebbe più facile, se fosse possibile un alias in stile c ++ - e hai solo bisogno di un posto in un file per sostituire una classe alias con l'implementazione da uno di essi.
Offler

RE-POST for EDIT @Offler Per quello che stai descrivendo il suono hai bisogno di qualcosa come una Factory con interfacce. IColorScheme oColorScheme = ColorSchemeFactory.Create(); Inoltre, potresti voler esaminare l' iniezione di dipendenza
percebus

2

È possibile passare all'utilizzo di un'interfaccia?

Forse potresti creare un file IColorScheme un'interfaccia che tutte le classi implementano?

Questo funzionerebbe bene con il modello di fabbrica come mostrato da Chris Marasti-Georg


Potrebbe essere, ma non ho intenzione di dedicare più tempo a questo piuttosto che rinominare la classe che è lo schema di colori "corrente" da utilizzare.
Ian Boyd

0

È una risposta parziale molto tardiva, ma se si definisce la stessa classe "ColorScheme", nello stesso spazio dei nomi "Outlook", ma in assembly separati, uno chiamato Outlook2003 e l'altro Outlook2007, tutto ciò che è necessario fare è fare riferimento all'assembly appropriato .

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.