Wie kann ich einen Klassennamen in C # aliasisieren, ohne jeder Datei, die die Klasse verwendet, eine Codezeile hinzufügen zu müssen?

82

Ich möchte einen Alias ​​für einen Klassennamen erstellen. Die folgende Syntax wäre perfekt:

public class LongClassNameOrOneThatContainsVersionsOrDomainSpecificName
{
   ...
}

public class MyName = LongClassNameOrOneThatContainsVersionOrDomainSpecificName;

aber es wird nicht kompiliert.


Beispiel

Hinweis Dieses Beispiel dient nur der Übersichtlichkeit. Versuchen Sie nicht, dieses spezielle Problem zu lösen, indem Sie vorschlagen, das Design des gesamten Systems zu ändern. Das Vorhandensein oder Fehlen dieses Beispiels ändert nichts an der ursprünglichen Frage.

Einige vorhandene Codes hängen vom Vorhandensein einer statischen Klasse ab:

public static class ColorScheme
{
   ...
}

Dieses Farbschema ist das Outlook 2003-Farbschema. Ich möchte ein Outlook 2007-Farbschema einführen und dabei das Outlook 2003-Farbschema beibehalten:

public static class Outlook2003ColorScheme
{
   ...
}

public static class Outlook2007ColorScheme
{
   ...
}

Aber ich bin immer noch mit der Tatsache konfrontiert, dass der Code vom Vorhandensein einer statischen Klasse namens abhängt ColorScheme. Mein erster Gedanke war, eine ColorSchemeKlasse zu erstellen , die ich entweder erben werde Outlook2003oder Outlook2007:

public static class ColorScheme : Outlook2007ColorScheme
{
}

Sie können jedoch nicht von einer statischen Klasse erben.

Mein nächster Gedanke war, die statische ColorSchemeKlasse zu erstellen , aber make Outlook2003ColorSchemeund Outlook2007ColorSchemeKlassen nicht statisch. Dann kann eine statische Variable in der statischen ColorSchemeKlasse auf eines der "echten" Farbschemata verweisen:

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

private class CustomColorScheme 
{ 
   ...
}

private class Outlook2008ColorScheme : CustomColorScheme 
{
    ...
}

private class Outlook2003ColorScheme : CustomColorScheme 
{
   ...
}

Dafür müsste ich jedoch eine Klasse konvertieren, die vollständig aus schreibgeschützten statischen Farben besteht, in überschreibbare Eigenschaften, und dann ColorSchememüsste meine Klasse die 30 verschiedenen Eigenschafts-Getter in das enthaltene Objekt einbinden .

Das ist einfach zu viel Tippen.

Mein nächster Gedanke war also, die Klasse zu aliasen:

public static ColorScheme = Outlook2007ColorScheme;

Das lässt sich aber nicht kompilieren.

Wie kann ich eine statische Klasse in einen anderen Namen aliasen?


Update: Kann jemand bitte die Antwort "Sie können dies nicht in C # tun" hinzufügen , damit ich dies als akzeptierte Antwort markieren kann. Jeder andere, der die Antwort auf dieselbe Frage wünscht, findet diese Frage, die akzeptierte Antwort und eine Reihe von Problemumgehungen, die nützlich sein können oder nicht.

Ich möchte diese Frage nur abschließen.

Ian Boyd
quelle
Sie können auch die Antwort von Chris akzeptieren, auch wenn Sie sie nicht implementieren möchten
devio
2
Es ist nicht die Antwort, es ist eine Problemumgehung. Die Antwort ist, dass Sie dies nicht können - zumindest bis jemand vorbeikommt und die eigentliche Syntax dafür veröffentlicht.
Ian Boyd
1
Für alle, die hierher kommen, ist die akzeptierte Antwort falsch, da der Kommentar mit der höchsten Bewertung in VS 2010- und VS 2017 c # -Projekten, an denen ich arbeite, einwandfrei funktioniert. Der vollständig qualifizierte Namespace muss verwendet werden, um die Klasse beim Einrichten des Alias ​​anzugeben. Nach dem Einrichten funktioniert der Alias ​​jedoch innerhalb des definierten Bereichs.
J-Americano
Ich musste Ians Antwort und seine Kommentare ausführlich lesen, bevor ich verstand, wonach er suchte. Er möchte einen Klassenalias an einer Stelle deklarieren , anstatt ihn oben in jede Datei einfügen zu müssen, die auf die Klasse verweist. Mir sind keine stark typisierten Sprachen bekannt, die dies unterstützen. (Wenn jemand eine solche Sprache kennt, würde ich gerne davon erfahren.) Ich habe den Titel bearbeitet, um dies klarer zu machen.
ToolmakerSteve
Übrigens für alle, die versuchen, etwas Ähnliches zu tun: Wenn es sich um Klassen handelt, die Sie definieren, besteht der C # -Ansatz darin, eine zu definieren interface, die alle Ihre Klassen implementieren. Wie in der Antwort von chills42 erwähnt . Sie können dann einen "Service" oder eine "Factory" definieren, die ein Objekt zurückgibt, das diese Schnittstelle implementiert, abhängig von den aktuellen Umständen (z. B. Plattform / Betriebssystem) oder einer Konfigurationsdatei.
ToolmakerSteve

Antworten:

123

Das kannst du nicht . Das nächstbeste, was Sie tun können , ist, usingDeklarationen in den Dateien zu haben, die die Klasse verwenden.

Sie können beispielsweise den abhängigen Code mithilfe eines Importalias (als Quasi- typedefErsatz) neu schreiben :

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

Leider muss dies in jeden Bereich / jede Datei gehen, die den Namen verwendet.

Ich weiß daher nicht, ob dies in Ihrem Fall praktisch ist.

Konrad Rudolph
quelle
9
Wenn es oben in der Datei stehen könnte, die die ursprüngliche Klasse enthält: Es wäre großartig. Aber das usingmuss zu jedem kaputten Code hinzugefügt werden. Außerdem wird negiert, dass der Wert einen einzelnen Alias ​​hat, mit dem ich alle Benutzer der vorhandenen ColorSchemeKlasse auf eine neue Klasse umstellen kann - ohne Änderungen. Mit anderen Worten: Ich möchte die ColorSchemeKlasse einer anderen Klasse zuordnen.
Ian Boyd
Gibt es eine Möglichkeit, dasselbe zu erreichen und den Alias ​​mit Vererbung zu verbreiten? dh alle Klassen, die MyClass erweitern, können ColorScheme anstelle von.Fully.Qualified ... ColorScheme verwenden, indem sie einfach die using-Anweisung in die MyClass-Quelldatei einfügen?
Florian Burel
Nun, es war sehr praktisch für meinen Fall. Schließlich hört C # auf, meine Dateipfade zu zeichnen.
ElDoRado1239
25

Sie können einen Alias ​​für Ihre Klasse erstellen, indem Sie folgende Codezeile hinzufügen:

using Outlook2007ColorScheme = YourNameSpace.ColorScheme;
mohammedn
quelle
Der Name 'ColorScheme' existiert im aktuellen Kontext nicht
Ian Boyd
6
Sie benötigen Fully.Qualified.Namespace.Of.ColorScheme
Jamie Pate
Ich dachte, in C # könnten nur Alias-Namespaces (keine Klassen) auf diese Weise verwendet werden, während Sie in VB.Net Namespaces oder Klassen mit Alias ​​verwenden können Imports. Liege ich falsch?
Nick
Sie benötigen keinen vollständig qualifizierten Namen, wenn Sie die usingDirektive in den Namespace einfügen, z. B. wenn Sie einen Alias ​​Ihrer eigenen Klasse benötigen.
Elvedin Hamzagic
13

Sie können einen Klassennamen in C # nicht wirklich als Alias ​​verwenden. Sie können eine Problemumgehung mit der Verwendung üben, wie in anderen Antworten erläutert.

Es gibt Dinge, die Sie tun können, ohne einen Klassennamen in C # zu aliasen.

Um die ursprüngliche Frage zu beantworten: Sie können einen Klassennamen in C # nicht als Alias ​​verwenden.


Update: Die Leute sind verwirrt, warum usinges nicht funktioniert. Beispiel:

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

Und alles funktioniert. Jetzt möchte ich eine neue Klasse und einen Alias dafür erstellen ColorScheme(damit kein Code geändert werden muss ):

ColorScheme.cs

using ColorScheme = Outlook2007ColorScheme;

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

Ohh, es tut mir leid. Dieser Code wird nicht kompiliert:

Geben Sie hier die Bildbeschreibung ein

Meine Frage war , wie man alias eine Klasse in C #. Es kann nicht gemacht werden. Es gibt Dinge, die ich tun kann, die einen Klassennamen in C # nicht aliasen:

  • Änderung jeder, hängt davon ab , ColorSchemean using ColorSchemestatt (Codeänderung Abhilfe , weil ich kann nicht Alias)
  • Ändern Sie jeden, der darauf angewiesen ist ColorScheme, ein Factory-Muster zu verwenden, in eine polymorphe Klasse oder Schnittstelle (Problemumgehung für Codeänderungen, da ich keinen Alias ​​erstellen kann).

Bei diesen Problemumgehungen wird jedoch vorhandener Code beschädigt: keine Option.

Wenn Leute von der Anwesenheit einer ColorSchemeKlasse abhängig sind , muss ich tatsächlich eine ColorSchemeKlasse kopieren / einfügen .

Mit anderen Worten: Ich kann keinen Klassennamen in C # aliasen.

Dies steht im Gegensatz zu anderen objektorientierten Sprachen, in denen ich den Alias ​​definieren könnte:

ColorScheme = Outlook2007ColorScheme

und ich wäre fertig.

Ian Boyd
quelle
20
Sie können einen Klassennamen in C # absolut aliasisieren. "using <alias_name> = <fully_qualified_name>;"
Clemahieu
6
Wie @clemahieu sagte, Sie können absolut einen Klassennamen alias, Sie müssen nur den vollständig qualifizierten Namen verwenden. Wenn Sie eine generische Klasse aliasen, müssen Sie möglicherweise das generische Klassenqualifikationsmerkmal hinzufügen. Zum Beispiel: using ShortName = MyNamespace.SubNamespace.GenericClass <MyType>;
Dan Morphis
10
Downvote - Sie haben angegeben, dass Sie einen Klassennamen in C # nicht als Alias ​​verwenden können. Sie können. Was Sie nicht tun können, ist, eine Klasse so zu aliasieren, wie Sie es möchten - was eine durchaus berechtigte Anforderung ist, aber Ihre Aussage ist falsch.
Tom W
8
Wie mehrere Poster hervorgehoben haben, verhindert die Verwendung des qualifizierten Namens in keiner Weise das Aliasing. Sie können die Klasse aliasen. Sie müssen dazu nur den vollständig qualifizierten Namen verwenden. Dies ist möglicherweise unpraktisch, macht jedoch die Aussage "Sie können einen Klassennamen in C # nicht als Alias ​​verwenden" nicht wahr. Vielleicht unterscheidet sich die Art und Weise, wie Aliasing in C # funktioniert, von der erwarteten. Das ist in Ordnung - wenn das der Fall ist, geben Sie das an. Sie können jedoch einen Klassennamen in C # aliasen, da in der Spezifikation angegeben ist, dass Sie dies gemäß der bereitgestellten Definition tun können.
Tom W
5
Mir gefällt, wie wir Programmierer unsere Aussagen zwischen den Zeilen machen. Was Ian wirklich sagt, ist, dass C # dumm und kaputt ist, weil es keine einfache grundlegende Sache kann, die jeder tun möchte und sollte. Er hat Recht - ob eine bestimmte Semantik Sie glücklich macht oder nicht.
IQpierce
12

Sie möchten einen ( Factory | Singleton ), abhängig von Ihren Anforderungen. Die Voraussetzung ist, dass der Client-Code nicht wissen muss, welches Farbschema er erhält. Wenn das Farbschema anwendungsweit sein soll, sollte ein Singleton in Ordnung sein. Wenn Sie unter verschiedenen Umständen ein anderes Schema verwenden, ist wahrscheinlich ein Factory-Muster der richtige Weg. In beiden Fällen muss der Code nur an einer Stelle geändert werden, wenn sich das Farbschema ändern muss.

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; }
    }
}
Chris Marasti-Georg
quelle
Dies sieht weniger nach einer Fabrik als nach einem schwachen Versuch eines Singleton-Musters aus. Eine Fabrik würde die Erstellungsmethode eher parametrisieren. Sie hätten eher etwas wie: public static ColorScheme GetColorScheme (String-Deskriptor);
OwenP
Richtig - die Grundidee besteht darin, sicherzustellen, dass sich der Code nur an einer Stelle ändern muss, wenn Office 2012 herauskommt.
Chris Marasti-Georg
1
Dies funktioniert definitiv, aber es ist sicherlich eine unternehmensweite Lösung für ein einfaches Problem.
Ian Boyd
10

Versuche dies:

using ColorScheme=[fully qualified].Outlook2007ColorScheme
dpurrington
quelle
Der Name 'ColorScheme' existiert im aktuellen Kontext nicht
Ian Boyd
2
Sie benötigen Fully.Qualified.Namespace.Of.ColorScheme
Jamie Pate
6

Ich füge diesen Kommentar für Benutzer hinzu, die dies finden, lange nachdem OP ihre "Antwort" akzeptiert hat. Das Aliasing in C # funktioniert durch Angabe des Klassennamens unter Verwendung des vollständig qualifizierten Namespace. Einer der definierten Aliasnamen kann innerhalb seines Gültigkeitsbereichs verwendet werden. Beispiel.

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
  }

}

Entschuldigung für den schnell eingegebenen Code, aber hoffentlich wird erklärt, wie dies implementiert werden sollte, damit Benutzer nicht irreführen, zu glauben, dass dies in C # nicht möglich ist.

J-Americano
quelle
Dies wäre noch deutlicher , wenn man die zeigte Erklärung der anderen Klasse: namespace Fully.Qualified.Namespace{ public class Example {... public void DoStuff(){... }... } }.
ToolmakerSteve
1
Um klar zu sein, das ist anders als das, was Ian sucht. Ian hat eine Situation, in der er die Quelldateien, die sich auf eine Klasse beziehen, nicht ändern kann (oder will). Er möchte eine Möglichkeit, eine Änderung nur an einer Stelle in seiner Anwendung oder Bibliothek vorzunehmen , was zu einer Klasse mit dem gewünschten Namen führt, die jeder andere Code verwenden kann [ohne diese "using" -Anweisung zu mehreren Quellen hinzufügen zu müssen Dateien - zum Beispiel kann diese Quelle möglicherweise nicht geändert werden].
ToolmakerSteve
4

Das Aliasing der Art und Weise, wie Sie es tun möchten, funktioniert in C # nicht. Dies liegt daran, dass das Aliasing über das erfolgtusing Direktive erfolgt, die auf die betreffende Datei / den betreffenden Namespace beschränkt ist. Wenn Sie 50 Dateien haben, die den alten Klassennamen verwenden, bedeutet dies, dass 50 Stellen aktualisiert werden müssen.

Trotzdem denke ich, dass es eine einfache Lösung gibt, um Ihre Codeänderung so gering wie möglich zu halten. Machen Sie die ColorSchemeKlasse zu einer Fassade für Ihre Aufrufe der tatsächlichen Klassen mit der Implementierung und verwenden Sie die usingin dieser Datei, um zu bestimmen, welche ColorSchemeSie verwenden.

Mit anderen Worten, tun Sie dies:

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

Dann ändern Sie in Ihrem Code dahinter nichts:

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

Sie können dann die Werte ColorSchemevon aktualisieren, indem Sie eine Codezeile aktualisieren (using CurrentColorScheme = Outlook2008ColorScheme; ) .

Ein paar Bedenken hier:

  • Jede neue Methode oder Eigenschaftsdefinition muss dann an zwei Stellen hinzugefügt werden, zur ColorSchemeKlasse und zur Outlook2007ColorSchemeKlasse. Dies ist zusätzliche Arbeit, aber wenn es sich um echten Legacy-Code handelt, sollte dies nicht häufig vorkommen. Als Bonus wird der Code inColorScheme so einfach, dass jeder mögliche Fehler sehr offensichtlich ist.
  • Diese Verwendung statischer Klassen erscheint mir nicht selbstverständlich. Ich würde wahrscheinlich versuchen, den Legacy-Code zu überarbeiten, um dies anders zu machen, aber ich verstehe auch, dass Ihre Situation dies möglicherweise nicht zulässt.
  • Wenn Sie bereits eine ColorSchemeKlasse haben, die Sie ersetzen, können dieser und alle anderen Ansätze ein Problem darstellen. Ich würde empfehlen, dass Sie diese Klasse in etwas umbenennen ColorSchemeOldund dann über darauf zugreifen using CurrentColorScheme = ColorSchemeOld;.
Timothy
quelle
3

Ich nehme an, Sie können immer von der Basisklasse erben, ohne dass etwas hinzugefügt wird

public class Child : MyReallyReallyLongNamedClass {}

AKTUALISIEREN

Aber wenn Sie die Möglichkeit haben, sich classselbst umzugestalten : Ein Klassenname ist normalerweise unnötig lang, da namespaces fehlt .

Wenn Sie sehen , wie Fälle ApiLoginUser, DataBaseUser,WebPortalLoginUser , ist in der Regel Hinweis auf fehlende namespacewegen der Furcht , dass der Name Userkönnte Konflikt.

In diesem Fall können Sie jedoch einen namespaceAlias ​​verwenden , wie in den obigen Beiträgen erwähnt

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

Beachten Sie, wie die classNamen alle sind User, aber in verschiedenen namespaces. Zitieren PEP-20: Zen of Python :

Namespaces sind eine großartige Idee - lasst uns mehr davon machen!

Hoffe das hilft

Percebus
quelle
2
immer, es sei denn, Sie können nicht: zB versiegelte Klasse
Mikus
aber das wird in vielen Fällen nicht funktionieren. zB öffentliche Klasse MyList: List {} - wenn Sie später MyList versuchen xyz = Something.ToList (); du wirst stecken bleiben.
Offler
@Offler Sie könnten (und sollten wahrscheinlich) entweder auf newSchlüsselwörter für solche Methoden zurückgreifen oder sogar Ihre eigenen ExtensionMethods entwickeln, oder? In jedem Fall bin ich der festen Überzeugung, dass Sie immer Vanilla Collection-Klassen (z. B. Dictionary, List, IEnumerable, IQueryable usw.) mit benutzerdefinierten Models / ViewModels / POCOs verwenden sollten. Wie Mvc es ausdrückt: Konvention über Konfiguration
Percebus
@percebus funktioniert nicht in allen Fällen. Ich versuche, Vintage-Code zu transformieren, wenn Teile eine API verwenden, die nicht mehr unterstützt wird, auf eine neuere. Durign-Transformationscode wird von anderen geändert und sollte weiterhin ausführbar sein - daher sollten beide gerade jetzt verwendbar sein. Es wäre einfacher, Dinge über 700.000 LOC (ohne Kommentare) zu konvergieren und sie dennoch ausführbar zu machen, wenn ein Alias ​​im C ++ - Stil möglich wäre - und Sie benötigen nur eine Stelle in einer Datei, um eine Aliasklasse durch die Implementierung von beiden zu ersetzen.
Offler
RE-POST für EDIT @Offler Für das, was Sie beschreiben, brauchen Sie etwas wie eine Factory mit Schnittstellen. IColorScheme oColorScheme = ColorSchemeFactory.Create(); Vielleicht möchten Sie auch in Dependency Injection
Percebus
2

Ist es möglich, auf eine Schnittstelle umzusteigen?

Vielleicht könnten Sie eine IColorSchemeSchnittstelle erstellen , die alle Klassen implementieren?

Dies würde gut mit dem Fabrikmuster funktionieren, wie es von Chris Marasti-Georg gezeigt wird

Schüttelfrost42
quelle
Es könnte sein, aber ich werde keine Zeit mehr damit verbringen, anstatt die Klasse umzubenennen, die das "aktuelle" Farbschema ist.
Ian Boyd
0

Es ist eine sehr späte Teilantwort. Wenn Sie jedoch dieselbe Klasse 'ColorScheme' im selben Namespace 'Outlook' definieren, jedoch in separaten Assemblys, eine mit dem Namen Outlook2003 und die andere mit Outlook2007, müssen Sie nur auf die entsprechende Assembly verweisen .

Mark Farmiloe
quelle
0

Während die von Ihnen angeforderte Funktionalität nicht vorhanden ist und meine Antwort Ihre Frage per se nicht beantwortet, ist es möglich, die ColorScheme-Klasse intakt zu lassen und mit Veraltet zu markieren Attribut und dann die beiden anderen neuen Farbschema-Klassen hinzuzufügen.

Dies würde keine systemischen Änderungen erfordern und hält die veraltete Klasse isoliert.

rauben
quelle