Jak utworzyć alias nazwy klasy w języku C # bez konieczności dodawania wiersza kodu do każdego pliku, który używa tej klasy?

88

Chcę utworzyć alias dla nazwy klasy. Następująca składnia byłaby idealna:

public class LongClassNameOrOneThatContainsVersionsOrDomainSpecificName
{
   ...
}

public class MyName = LongClassNameOrOneThatContainsVersionOrDomainSpecificName;

ale się nie skompiluje.


Przykład

Uwaga Ten przykład podano tylko dla wygody. Nie próbuj rozwiązywać tego konkretnego problemu, sugerując zmianę projektu całego systemu. Obecność lub brak tego przykładu nie zmienia pierwotnego pytania.

Część istniejącego kodu zależy od obecności klasy statycznej:

public static class ColorScheme
{
   ...
}

Ten schemat kolorów to schemat kolorów programu Outlook 2003. chcę wprowadzić schemat kolorów programu Outlook 2007, zachowując schemat kolorów programu Outlook 2003:

public static class Outlook2003ColorScheme
{
   ...
}

public static class Outlook2007ColorScheme
{
   ...
}

Ale wciąż mam do czynienia z faktem, że kod zależy od obecności statycznej klasy o nazwie ColorScheme. Moją pierwszą myślą było stworzenie ColorSchemeklasy, którą odziedziczę po jednym Outlook2003lub Outlook2007:

public static class ColorScheme : Outlook2007ColorScheme
{
}

ale nie możesz dziedziczyć z klasy statycznej.

Następną moją myślą było stworzenie ColorSchemeklasy statycznej , ale make Outlook2003ColorSchemei Outlook2007ColorSchemeklasy nie są statyczne. Następnie zmienna statyczna w ColorSchemeklasie statycznej może wskazywać na „prawdziwy” schemat kolorów:

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

private class CustomColorScheme 
{ 
   ...
}

private class Outlook2008ColorScheme : CustomColorScheme 
{
    ...
}

private class Outlook2003ColorScheme : CustomColorScheme 
{
   ...
}

ale to wymagałoby ode mnie konwersji klasy składającej się całkowicie ze statycznych kolorów tylko do odczytu na właściwości, które można zastąpić, a następnie moja ColorSchemeklasa musiałaby mieć 30 różnych funkcji pobierających właściwości, które zostałyby przeniesione do zawartego obiektu.

To po prostu za dużo pisania.

Więc moją następną myślą było nadanie aliasu klasie:

public static ColorScheme = Outlook2007ColorScheme;

Ale to się nie kompiluje.

Jak mogę utworzyć alias dla klasy statycznej pod inną nazwą?


Aktualizacja: Czy ktoś może dodać odpowiedź „Nie możesz tego zrobić w C #” , więc mogę oznaczyć to jako zaakceptowaną odpowiedź. Każdy, kto chce odpowiedzieć na to samo pytanie, znajdzie to pytanie, zaakceptowaną odpowiedź i szereg obejść, które mogą być przydatne lub nie.

Chcę tylko zamknąć to pytanie.

Ian Boyd
źródło
równie dobrze możesz zaakceptować odpowiedź Chrisa, nawet jeśli nie chcesz jej wdrażać
devio,
2
To nie jest odpowiedź, to obejście. Odpowiedź jest taka, że ​​nie możesz - przynajmniej dopóki ktoś nie podejdzie i nie opublikuje właściwej składni, aby to zrobić.
Ian Boyd,
1
Dla każdego, kto tu przychodzi, zaakceptowana odpowiedź jest nieprawidłowa, ponieważ najwyżej oceniony komentarz działa dobrze w projektach c # VS 2010 i VS 2017, nad którymi pracuję. Podczas konfigurowania aliasu należy użyć w pełni kwalifikowanej przestrzeni nazw, aby określić klasę, ale po skonfigurowaniu alias działa w zdefiniowanym zakresie.
J-Americano
Musiałem bardzo szczegółowo przeczytać odpowiedź Iana i jego komentarze, zanim zrozumiałem, czego szuka. Chce zadeklarować alias klasy w jednym miejscu , zamiast dodawać go na początku każdego pliku, który odwołuje się do klasy. Nie znam żadnych silnie wpisanych języków, które to obsługują. (Jeśli ktoś zna taki język, chciałbym się o nim dowiedzieć.) Zredagowałem tytuł, aby był bardziej zrozumiały.
ToolmakerSteve
BTW, dla każdego, kto próbuje zrobić coś podobnego: jeśli są to klasy, które definiujesz, podejście C # polega na zdefiniowaniu an interface, który implementują wszystkie twoje klasy. Jak wspomniano w odpowiedzi Chills42 . Następnie można zdefiniować „usługę” lub „fabrykę”, która zwraca obiekt, który implementuje ten interfejs, w zależności od bieżących okoliczności (np. Platforma / system operacyjny) lub w pliku konfiguracyjnym.
ToolmakerSteve

Odpowiedzi:

131

Nie możesz . Następna najlepsza rzecz można zrobić, to mieć usingdeklaracje w plikach, które wykorzystują klasę.

Na przykład, możesz przepisać zależny kod używając aliasu importu (jako quasi- typedefsubstytut):

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

Niestety musi to znaleźć się w każdym zasięgu / pliku, który używa tej nazwy.

Dlatego nie wiem, czy jest to praktyczne w twoim przypadku.

Konrad Rudolph
źródło
9
Gdyby mógł znaleźć się na początku pliku zawierającego oryginalną klasę: byłoby świetnie. Ale usingnależy dodać do całego zepsutego kodu. A także neguje wartość posiadania pojedynczego aliasu, co pozwala mi przełączyć wszystkich użytkowników istniejącej ColorSchemeklasy na użycie nowej klasy - bez zmian. Innymi słowy: chcę aliasować ColorSchemeklasę do innej klasy.
Ian Boyd
Czy istnieje sposób, aby osiągnąć to samo i propagować alias z dziedziczeniem. tzn. wszystkie klasy rozszerzające MyClass będą mogły używać ColorScheme zamiast.Fully.Qualified ... ColorScheme, po prostu dodając instrukcję using w pliku źródłowym MyClass?
Florian Burel
Cóż, było to bardzo praktyczne w moim przypadku. Wreszcie C # przestanie rysować moje ścieżki plików.
ElDoRado1239
25

Możesz utworzyć alias dla swojej klasy, dodając następujący wiersz kodu:

using Outlook2007ColorScheme = YourNameSpace.ColorScheme;
mohammedn
źródło
Nazwa „ColorScheme” nie istnieje w obecnym kontekście
Ian Boyd
7
potrzebujesz Fully.Qualified.Namespace.Of.ColorScheme
Jamie Pate
Pomyślałem, że w C # można aliasować tylko przestrzenie nazw (nie klasy) w ten sposób, podczas gdy w VB.Net można aliasować przestrzenie nazw lub klasy za pomocą Imports. Czy się mylę?
Nick
Nie potrzebujesz pełnej nazwy, jeśli umieścisz usingdyrektywę w jej przestrzeni nazw, np. Gdy potrzebujesz aliasu własnej klasy.
Elvedin Hamzagic
12

Chcesz ( Factory | Singleton ), w zależności od twoich wymagań. Założeniem jest to, aby kod klienta nie musiał wiedzieć, jaki schemat kolorów otrzymuje. Jeśli schemat kolorów ma być szeroki w aplikacji, pojedynczy powinien wystarczyć. Jeśli możesz użyć innego schematu w innych okolicznościach, prawdopodobnie najlepszym rozwiązaniem będzie wzorzec Factory. Tak czy inaczej, gdy trzeba zmienić schemat kolorów, kod wystarczy zmienić tylko w jednym miejscu.

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
źródło
Wygląda to mniej na fabrykę, a bardziej na słabą próbę stworzenia pojedynczego wzoru. Fabryka byłaby bardziej skłonna sparametryzować metodę tworzenia; miałbyś coś więcej na przykład: public static ColorScheme GetColorScheme (deskryptor ciągu);
OwenP
To prawda - podstawową ideą jest upewnienie się, że gdy pojawi się Office 2012, kod będzie się zmieniał tylko w 1 miejscu.
Chris Marasti-Georg
1
To z pewnością działa, ale z pewnością jest korporacyjnym rozwiązaniem prostego problemu.
Ian Boyd
11

Nie można utworzyć aliasu nazwy klasy w języku C #.

Są rzeczy, które możesz zrobić, a nie aliasowanie nazwy klasy w języku C #.

Ale odpowiadając na pierwotne pytanie: nie możesz aliasować nazwy klasy w C #.


Aktualizacja: Ludzie są zdezorientowani, dlaczego usingnie działa. Przykład:

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

I wszystko działa. Teraz chcę utworzyć nową klasę i alias ColorScheme do niej (aby nie trzeba było modyfikować kodu ):

ColorScheme.cs

using ColorScheme = Outlook2007ColorScheme;

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

Och, przepraszam. Ten kod nie kompiluje się:

wprowadź opis obrazu tutaj

Moje pytanie dotyczyło aliasu klasy w C #. Nie da się tego zrobić. Są rzeczy, które mogę zrobić, że są nie aliasing nazwę klasy w języku C #:

  • zmiana każdy, kto zależy ColorSchemeaby using ColorSchemezamiast (zmiana obejście kodu, ponieważ nie mogę alias)
  • zmień wszystkich, od których zależy, ColorSchemeaby używały wzorca fabrycznego, im polimorficzną klasę lub interfejs (obejście zmiany kodu, ponieważ nie mogę aliasu)

Ale te obejścia obejmują złamanie istniejącego kodu: nie jest to opcja.

Jeśli ludzie polegają na obecności ColorSchemeklasy, muszę faktycznie skopiować / wkleić plikColorScheme klasę.

Innymi słowy: nie mogę aliasować nazwy klasy w C #.

Kontrastuje to z innymi językami obiektowymi, w których mógłbym zdefiniować alias:

ColorScheme = Outlook2007ColorScheme

i byłbym skończony.

Ian Boyd
źródło
22
Absolutnie możesz aliasować nazwę klasy w C #. "using <alias_name> = <fully_qualified_name>;"
clemahieu
8
LIke @clemahieu powiedział, że absolutnie możesz aliasować nazwę klasy, po prostu musisz użyć w pełni kwalifikowanej nazwy. Ponadto w przypadku tworzenia aliasów klasy ogólnej może być konieczne dodanie kwalifikatora klasy ogólnej. Na przykład: using ShortName = MyNamespace.SubNamespace.GenericClass <MyType>;
Dan Morphis,
11
Głos przeciw - stwierdziłeś „Nie możesz aliasować nazwy klasy w C #”. Możesz. Czego nie może zrobić, to alias klasy w sposób ty chcesz - co jest całkiem uzasadnione wymaganie, ale twoje stwierdzenie jest błędne.
Tom W
8
Jak zauważyło kilka plakatów, konieczność używania nazwy kwalifikowanej w żaden sposób nie zabrania aliasingu. Państwo może aliasu klasę. Aby to zrobić, wystarczy użyć w pełni kwalifikowanej nazwy. Może się to wydawać niewygodne, ale nie powoduje to, że stwierdzenie „Nie można aliasować nazwy klasy w języku C #” jest prawdziwe. Być może sposób, w jaki działa aliasowanie w C #, różni się od oczekiwanego. W porządku - jeśli tak jest, powiedz to. Ale może aliasu nazwy klasy w języku C #, ponieważ stany specyfikacji, że można to zrobić, zgodnie z definicją, jakie zapewnia.
Tom W
5
Podoba mi się sposób, w jaki my, programiści, będziemy składać oświadczenia między wierszami. Ian tak naprawdę mówi, że C # jest głupi i zepsuty, ponieważ nie może zrobić prostej podstawowej rzeczy, którą każdy chciałby zrobić i powinien umieć zrobić. Ma rację - czy konkretna semantyka cię uszczęśliwia.
IQpierce
10

Spróbuj tego:

using ColorScheme=[fully qualified].Outlook2007ColorScheme
dpurrington
źródło
Nazwa „ColorScheme” nie istnieje w obecnym kontekście
Ian Boyd
2
potrzebujesz Fully.Qualified.Namespace.Of.ColorScheme
Jamie Pate
6

Dodaję ten komentarz dla użytkowników, którzy znaleźli to długo po tym, jak OP zaakceptował ich „odpowiedź”. Aliasowanie w C # działa przez określenie nazwy klasy przy użyciu jej w pełni kwalifikowanej przestrzeni nazw. Jeden zdefiniowany, alias może być używany w jego zakresie. Przykład.

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
  }

}

Przepraszamy za szybko wpisany kod, ale miejmy nadzieję, że wyjaśnia, jak należy to zaimplementować, aby użytkownicy nie wprowadzali w błąd, wierząc, że nie można tego zrobić w C #.

J-Americano
źródło
To byłoby jeszcze wyraźniejsze, jeśli pokazał deklarację drugiej klasy: namespace Fully.Qualified.Namespace{ public class Example {... public void DoStuff(){... }... } }.
ToolmakerSteve
1
Żeby było jasne, jest to coś innego niż to, czego szuka Ian. Ian ma sytuację, w której nie może (lub nie chce) zmieniać plików źródłowych, które odnoszą się do klasy. Chce sposobu na dokonanie zmiany tylko w jednym miejscu w swojej aplikacji lub bibliotece , w wyniku czego coś, co wydaje się być klasą o pożądanej nazwie, której może używać każdy inny kod [bez konieczności dodawania tej instrukcji "using" do wielu źródeł pliki - na przykład to źródło może nie być dostępne do zmiany].
ToolmakerSteve
4

Aliasowanie w sposób, w jaki chciałbyś to zrobić, nie zadziała w C #. Dzieje się tak, ponieważ aliasing jest wykonywany przez usingdyrektywę, która jest ograniczona do danego pliku / przestrzeni nazw. Jeśli masz 50 plików, które używają starej nazwy klasy, będzie to oznaczać 50 miejsc do zaktualizowania.

To powiedziawszy, myślę, że istnieje proste rozwiązanie, dzięki któremu zmiana kodu będzie jak najmniejsza. Spraw, aby ColorSchemeklasa stała się fasadą dla twoich wywołań klas rzeczywistych z implementacją i użyj usingw tym pliku, aby określić, której ColorSchemeużywasz.

Innymi słowy, zrób to:

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

Następnie w swoim kodzie z tyłu nic nie zmieniaj:

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

Następnie możesz zaktualizować wartości ColorScheme, aktualizując jeden wiersz kodu ( using CurrentColorScheme = Outlook2008ColorScheme;).

Kilka wątpliwości:

  • Każda nowa metoda lub definicja właściwości będzie musiała zostać dodana w dwóch miejscach, do ColorSchemeklasy i do Outlook2007ColorSchemeklasy. To dodatkowa praca, ale jeśli jest to prawdziwy starszy kod, nie powinno to być częste. Jako bonus, kod ColorSchemejest tak prosty, że każdy możliwy błąd jest bardzo oczywisty.
  • To użycie klas statycznych nie wydaje mi się naturalne; Prawdopodobnie spróbuję zreformować stary kod, aby zrobić to inaczej, ale rozumiem również, że twoja sytuacja może na to nie pozwalać.
  • Jeśli masz już ColorSchemeklasę, którą zastępujesz, to i każde inne podejście może stanowić problem. Radziłbym zmienić nazwę tej klasy na podobną ColorSchemeOld, a następnie uzyskać do niej dostęp za pośrednictwem using CurrentColorScheme = ColorSchemeOld;.
Tymotka
źródło
3

Przypuszczam, że zawsze można dziedziczyć z klasy bazowej bez niczego dodanego

public class Child : MyReallyReallyLongNamedClass {}

AKTUALIZACJA

Ale jeśli masz możliwość refaktoryzacji classsamej siebie: nazwa klasy jest zwykle niepotrzebnie długa z powodu braku namespaces.

Jeśli widzisz przypadki jak ApiLoginUser, DataBaseUser, WebPortalLoginUser, jest zwykle wskazanie braku namespacenależytej strachu, że nazwa Userkonfliktu sił.

W takim przypadku możesz jednak użyć namespacealiasu , jak wskazano w powyższych postach

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

Zwróć uwagę, że wszystkie classnazwy są User, ale w różnych namespace. Cytując PEP-20: Zen of Python :

Przestrzenie nazw to jeden wspaniały pomysł - zróbmy ich więcej!

Mam nadzieję że to pomoże

postrzegać
źródło
2
zawsze, chyba że nie możesz: np. klasa zamknięta
mikus
ale to nie zadziała w wielu przypadkach. np. publiczna klasa MyList: List {} - jeśli później spróbujesz MyList xyz = something.ToList (); utkniesz.
Offler
@Offler Możesz (i prawdopodobnie powinieneś) użyć jednego ze newsłów kluczowych dla takich metod lub nawet wymyślić własne ExtensionMethods, prawda? W każdym razie uważam, że zawsze powinieneś używać klas Vanilla Collection (tj. Dictionary, List, IEnumerable, IQueryable, itp.) Z niestandardowymi modelami / ViewModels / POCO. Jak twierdzi Mvc: Konwencja nad konfiguracją
postrzegamy
@percebus nie działa we wszystkich przypadkach. Próbuję przekształcić stary kod, w którym części używają interfejsu API, który nie jest już obsługiwany, na nowszy. kod transformacji podczas transformacji zostanie zmieniony przez innych i nadal powinien być możliwy do uruchomienia - więc oba powinny być teraz dostępne. convering Things ponad 700.000 LOC (bez komentarzy) i nadal pozwalać na to, by działało, byłoby łatwiej, gdyby alias w stylu c ++ byłby możliwy - i potrzebujesz tylko jednego miejsca w pliku, aby zastąpić klasę aliasu implementacją z którejkolwiek z nich.
Offler
RE-POST for EDIT @Offler Do tego, co opisujesz, potrzebujesz czegoś takiego jak Factory z interfejsami. IColorScheme oColorScheme = ColorSchemeFactory.Create(); Możesz również zajrzeć do Dependency Injection
perafbus
2

Czy można przejść na używanie interfejsu?

Może mógłbyś stworzyć IColorSchemeinterfejs, który implementują wszystkie klasy?

To działałoby dobrze ze wzorem fabrycznym, jak pokazał Chris Marasti-Georg

dreszcze 42
źródło
Może tak być, ale nie zamierzam spędzać więcej czasu nad tym, zamiast zmieniać nazwę klasy, która jest „bieżącym” schematem kolorów.
Ian Boyd
0

To bardzo późna odpowiedź częściowa - ale jeśli zdefiniujesz tę samą klasę `` ColorScheme '', w tej samej przestrzeni nazw `` Outlook '', ale w oddzielnych zestawach, jeden o nazwie Outlook2003, a drugi Outlook2007, wszystko, co musisz zrobić, to odwołać się do odpowiedniego zestawu .

Mark Farmiloe
źródło