Как создать псевдоним имени класса в C #, не добавляя строку кода в каждый файл, использующий этот класс?


87

Я хочу создать псевдоним для имени класса. Следующий синтаксис был бы идеальным:

public class LongClassNameOrOneThatContainsVersionsOrDomainSpecificName
{
   ...
}

public class MyName = LongClassNameOrOneThatContainsVersionOrDomainSpecificName;

но он не компилируется.


пример

Примечание. Этот пример предоставлен только для удобства. Не пытайтесь решить эту конкретную проблему, предлагая изменить конструкцию всей системы. Наличие или отсутствие этого примера не меняет исходный вопрос.

Некоторый существующий код зависит от наличия статического класса:

public static class ColorScheme
{
   ...
}

Эта цветовая схема является цветовой схемой Outlook 2003. Я хочу представить цветовую схему Outlook 2007, сохранив цветовую схему Outlook 2003:

public static class Outlook2003ColorScheme
{
   ...
}

public static class Outlook2007ColorScheme
{
   ...
}

Но я все еще сталкиваюсь с тем, что код зависит от наличия вызываемого статического класса ColorScheme. Моя первая мысль была создать ColorSchemeкласс , который я буду наследовать либо Outlook2003или Outlook2007:

public static class ColorScheme : Outlook2007ColorScheme
{
}

но вы не можете наследовать от статического класса.

Следующей моей мыслью было создать статический ColorSchemeкласс, но классы make Outlook2003ColorSchemeи Outlook2007ColorSchemeне статические. Тогда статическая переменная в статическом ColorSchemeклассе может указывать на любую «истинную» цветовую схему:

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

private class CustomColorScheme 
{ 
   ...
}

private class Outlook2008ColorScheme : CustomColorScheme 
{
    ...
}

private class Outlook2003ColorScheme : CustomColorScheme 
{
   ...
}

но для этого мне потребовалось бы преобразовать класс, состоящий только из статических цветов, доступных только для чтения, в переопределяемые свойства, и тогда моему ColorSchemeклассу потребовалось бы, чтобы 30 различных методов получения свойств были перенесены в содержащийся объект.

Это слишком много для набора текста.

Следующей моей мыслью было присвоить классу псевдоним:

public static ColorScheme = Outlook2007ColorScheme;

Но это не компилируется.

Как я могу присвоить статическому классу другое имя?


Обновление: может кто-нибудь добавить ответ «Вы не можете сделать это на C #» , чтобы я мог отметить это как принятый ответ. Любой другой, желающий получить ответ на тот же вопрос, найдет этот вопрос, принятый ответ и ряд обходных путей, которые могут оказаться полезными, а могут и не оказаться.

Я просто хочу закрыть этот вопрос.


с таким же успехом вы можете принять ответ Криса, даже если вы не хотите его реализовывать
devio

2
Это не ответ, это обходной путь. Ответ заключается в том, что вы не можете - по крайней мере, пока кто-нибудь не придет и не опубликует фактический синтаксис для этого.
Ян Бойд

1
Для всех, кто приходит сюда, принятый ответ неверен, поскольку комментарий с наивысшим рейтингом отлично работает в проектах VS 2010 и VS 2017 c #, над которыми я работаю. Полное пространство имен должно использоваться для указания класса при настройке псевдонима, но после настройки псевдоним работает в пределах определенной области.
J-Americano

Мне пришлось подробно прочитать ответ Яна и его комментарии, прежде чем я понял, что он ищет. Он хочет объявить псевдоним класса в одном месте , вместо того чтобы добавлять его в начало каждого файла, который ссылается на класс. Я не знаю ни одного строго типизированного языка, поддерживающего это. (Если кто-то знает такой язык, я хотел бы знать об этом.) Я отредактировал заголовок, чтобы сделать его более понятным.
ToolmakerSteve

Кстати, для всех, кто пытается сделать что-то подобное: если это классы, которые вы определяете, то подход C # состоит в том, чтобы определить interface, который реализуют все ваши классы. Как упоминалось в ответе chills42 . Затем вы можете определить «службу» или «фабрику», которая возвращает объект, реализующий этот интерфейс, в зависимости от текущих обстоятельств (например, платформы / ОС) или от конфигурационного файла.
ToolmakerSteve

Ответы:


129

Вы не можете . Следующее, что вы можете сделать, это иметь usingобъявления в файлах, которые используют этот класс.

Например, вы можете переписать зависимый код, используя псевдоним импорта (в качестве квазизамещения typedef):

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

К сожалению, это необходимо для каждой области / файла, использующего это имя.

Поэтому я не знаю, практично ли это в вашем случае.


9
Если бы он мог быть в верхней части файла, содержащего исходный класс: было бы здорово. Но это usingдолжно быть добавлено ко всему сломанному коду. И это также отрицает значение наличия единственного псевдонима, что позволяет мне переключить всех пользователей существующего ColorSchemeкласса на использование нового класса - без изменений. Другими словами: я хочу присвоить ColorSchemeкласс другому классу.
Ian Boyd

Есть ли способ добиться того же и распространить псевдоним с помощью наследования. т.е. весь класс, расширяющий MyClass, сможет использовать ColorScheme вместо .Fully.Qualified ... ColorScheme, просто добавив оператор using в исходный файл MyClass?
Флориан Бурел,

Что ж, в моем случае это было очень практично. Наконец, C # перестанет рисовать пути к моим файлам.
ElDoRado1239,

25

Вы можете создать псевдоним для своего класса, добавив эту строку кода:

using Outlook2007ColorScheme = YourNameSpace.ColorScheme;

Имя ColorScheme не существует в текущем контексте
Ян Бойд

7
вам нужно Fully.Qualified.Namespace.Of.ColorScheme
Джейми Пейт,

Я думал, что в C # можно использовать псевдонимы только пространств имен (а не классов), тогда как в VB.Net вы можете создавать псевдонимы пространств имен или классов, используя Imports. Я ошибся?
Ник

Вам не нужно полное имя, если вы помещаете usingдирективу в его пространство имен, например, когда вам нужен псевдоним вашего собственного класса.
Эльведин Хамзагич

12

Вам нужен ( Factory | Singleton ), в зависимости от ваших требований. Предпосылка состоит в том, чтобы сделать так, чтобы клиентский код не знал, какую цветовую схему он получает. Если цветовая схема должна подходить для всего приложения, подойдет синглтон. Если вы можете использовать другую схему в различных обстоятельствах, вероятно, вам подойдет шаблон Factory. В любом случае, когда необходимо изменить цветовую схему, нужно изменить код только в одном месте.

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

Это похоже не столько на фабрику, сколько на слабую попытку одноэлементного шаблона. Фабрика с большей вероятностью параметризует метод создания; у вас будет что-то более похожее на: public static ColorScheme GetColorScheme (строковый дескриптор);
OwenP

Верно - основная идея - сделать так, чтобы после выхода Office 2012 код изменился только в одном месте.
Крис Марасти-Георг

1
Это определенно работает, но это, безусловно, корпоративное решение простой проблемы.
Ian Boyd

11

Вы не можете использовать псевдоним класса в C #.

Есть вещи, которые можно сделать, не применяя псевдонима к имени класса в C #.

Но чтобы ответить на исходный вопрос: вы не можете использовать псевдоним имени класса в C #.


Обновление: люди не понимают, почему usingне работает. Пример:

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

И все работает. Теперь я хочу создать новый класс и псевдоним ColorScheme для него (чтобы не изменять код ):

ColorScheme.cs

using ColorScheme = Outlook2007ColorScheme;

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

Ох, извини. Этот код не компилируется:

введите описание изображения здесь

Мой вопрос заключался в том, как создать псевдоним класса в C #. Это невозможно. Есть вещи, которые я могу сделать, не используя псевдонима имени класса в C #:

  • изменение всех , кто зависит от ColorSchemeк using ColorSchemeвместо (обходного пути изменения коды , потому что я не могу псевдоним)
  • измените всех, кто зависит от ColorSchemeиспользования фабричного шаблона, на полиморфный класс или интерфейс (обходной путь изменения кода, потому что я не могу использовать псевдоним)

Но эти обходные пути включают нарушение существующего кода: не вариант.

Если люди зависят от наличия ColorSchemeкласса, мне нужно скопировать / вставить ColorSchemeкласс.

Другими словами: я не могу использовать псевдоним имени класса в C #.

Это контрастирует с другими объектно-ориентированными языками, где я мог определить псевдоним:

ColorScheme = Outlook2007ColorScheme

и я бы сделал.


21
Вы абсолютно можете использовать псевдоним класса в C #. "используя <alias_name> = <fully_qualified_name>;"
clemahieu

7
LIke @clemahieu сказал, что вы абсолютно можете использовать псевдоним имени класса, вам просто нужно использовать полное имя. Кроме того, если вы используете псевдоним универсального класса, вам может потребоваться добавить квалификатор универсального класса. Например: using ShortName = MyNamespace.SubNamespace.GenericClass <MyType>;
Дэн Морфис

11
Голосование против - вы заявили: «Вы не можете использовать псевдоним имени класса в C #». Вы можете. Что вы не можете сделать, так это создать псевдоним класса так, как вы хотите, что является вполне оправданным требованием, но ваше утверждение неверно.
Tom W

8
Как указывалось на нескольких плакатах, использование квалифицированного имени никоим образом не запрещает использование псевдонимов. Вы можете присвоить классу псевдоним. Для этого вам просто нужно использовать полное имя. Это может показаться вам неудобным, но это не делает утверждение «Вы не можете использовать псевдоним имени класса в C #» истинным. Возможно, способ работы псевдонимов в C # отличается от того, что вы ожидали. Это нормально - если это так, укажите это. Но вы можете использовать псевдоним имени класса в C #, потому что в спецификации указано, что вы можете это сделать в соответствии с определением, которое она предоставляет.
Tom W

5
Мне нравится, как мы, программисты, делаем утверждения между строк. На самом деле Ян говорит, что C # тупой и сломанный, потому что он не может делать простых элементарных вещей, которые кто-то хотел бы сделать и должен уметь. Он прав - независимо от того, нравится ли вам конкретная семантика.
IQpierce


6

Я добавляю этот комментарий для пользователей, обнаруживших это спустя много времени после того, как OP принял их «ответ». Псевдонимы в C # работают путем указания имени класса с использованием его полностью определенного пространства имен. Одно определенное имя псевдонима может использоваться в его области. Пример.

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
  }

}

Приносим извинения за быстро набираемый код, но, надеюсь, он объясняет, как это должно быть реализовано, чтобы пользователи не вводили в заблуждение, полагая, что это невозможно сделать на C #.


Это было бы еще более очевидным , если вы показали декларацию другого класса: namespace Fully.Qualified.Namespace{ public class Example {... public void DoStuff(){... }... } }.
ToolmakerSteve

1
Чтобы было ясно, это отличается от того, что ищет Ян. У Иана бывает ситуация, когда он не может (или не хочет) изменять исходные файлы, относящиеся к классу. Ему нужен способ внести изменения только в одном месте в своем приложении или библиотеке , в результате чего получится класс с желаемым именем, который может использовать весь другой код [без необходимости добавления этого оператора using в несколько источников файлы - например, этот источник может быть недоступен для изменения].
ToolmakerSteve

4

Псевдонимы, которые вы хотели бы сделать, не будут работать в C #. Это связано с тем, что сглаживание выполняется с помощью usingдирективы, которая ограничена рассматриваемым файлом / пространством имен. Если у вас есть 50 файлов, которые используют старое имя класса, это означает, что нужно обновить 50 мест.

Тем не менее, я думаю, что есть простое решение, позволяющее минимизировать изменения кода. Сделайте ColorSchemeкласс фасадом для ваших вызовов фактических классов с реализацией и используйте usingв этом файле, чтобы определить, что ColorSchemeвы используете.

Другими словами, сделайте так:

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

Затем в вашем коде ничего не меняйте:

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

Затем вы можете обновить значения ColorScheme, обновив одну строку кода ( using CurrentColorScheme = Outlook2008ColorScheme;).

Здесь есть пара проблем:

  • Затем каждое новое определение метода или свойства необходимо будет добавить в двух местах: в ColorSchemeкласс и в Outlook2007ColorSchemeкласс. Это дополнительная работа, но если это действительно устаревший код, это не должно происходить часто. В качестве бонуса код ColorSchemeнастолько прост, что любая возможная ошибка очень очевидна.
  • Мне не кажется естественным такое использование статических классов; Я бы, вероятно, попытался реорганизовать устаревший код, чтобы сделать это по-другому, но я также понимаю, что ваша ситуация может не позволить этого.
  • Если у вас уже есть ColorSchemeкласс, который вы заменяете, этот и любой другой подход могут стать проблемой. Я бы посоветовал вам переименовать этот класс во что-то вродеColorSchemeOld , а затем получить к нему доступ using CurrentColorScheme = ColorSchemeOld;.

3

Я полагаю, вы всегда можете наследовать от базового класса, ничего не добавляя

public class Child : MyReallyReallyLongNamedClass {}

ОБНОВИТЬ

Но если у вас есть возможность рефакторинга самого classсебя: имя класса обычно излишне длинное из-за отсутствияnamespace s.

Если вы видите случаи , как ApiLoginUser, DataBaseUser, WebPortalLoginUser, как правило , указывает на отсутствие namespaceиз - за страха , что имяUser может вступить в конфликт.

Однако в этом случае вы можете использовать namespaceпсевдоним , как было указано в сообщениях выше.

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

Обратите внимание, как все classимена User, но в разных namespaces. Цитата PEP-20: Zen of Python :

Пространства имен - одна отличная идея - давайте сделаем их больше!

Надеюсь это поможет


2
всегда, если вы не можете: например, закрытый класс
микус

но во многих случаях это не сработает. например, открытый класс MyList: List {} - если вы позже попробуете MyList xyz = something.ToList (); вы застрянете.
Offler

@Offler Вы можете (и, вероятно, должны) прибегнуть к любому newключевому слову для таких методов или даже придумать свои собственные ExtensionMethods, верно? В любом случае я твердо убежден в том, что вы всегда должны использовать классы vanilla Collection (например, Dictionary, List, IEnumerable, IQueryable и т. Д.) С пользовательскими моделями Models / ViewModels / POCO. Как заявляет Mvc: Соглашение
важнее

@percebus работает не во всех случаях. Я пытаюсь преобразовать старинный код, в котором части используют API, который больше не поддерживается, на более новый. Код преобразования durign будет изменен другими и должен по-прежнему работать - так что оба должны быть пригодны для использования прямо сейчас. преобразование вещей, превышающих 700000 LOC (без комментариев) и при этом позволяя его запускать, было бы проще, если бы был возможен псевдоним стиля С ++ - и вам нужно только одно место в файле, чтобы заменить класс псевдонима реализацией из любого из них.
Offler

RE-POST для EDIT @Offler Для того, что вы описываете звук, вам понадобится нечто вроде Factory с интерфейсами. IColorScheme oColorScheme = ColorSchemeFactory.Create(); Кроме того, вы можете изучить « Внедрение зависимостей»
Percebus

2

Можно ли перейти на использование интерфейса?

Возможно, вы могли бы создать IColorScheme интерфейс, который реализуют все классы?

Это будет хорошо работать с заводским шаблоном, как показано Крисом Марасти-Георгом.


Может быть, но я не собираюсь больше тратить на это время, вместо того чтобы переименовывать класс, который является «текущей» цветовой схемой, которую нужно использовать.
Ian Boyd

0

Это очень поздний частичный ответ, но если вы определяете один и тот же класс ColorScheme в том же пространстве имен Outlook, но в отдельных сборках, одна называется Outlook2003, а другая Outlook2007, тогда все, что вам нужно сделать, это ссылаться на соответствующую сборку .

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.