Como faço para criar um alias para um nome de classe em C #, sem precisar adicionar uma linha de código a cada arquivo que usa a classe?

87

Quero criar um alias para o nome de uma classe. A seguinte sintaxe seria perfeita:

public class LongClassNameOrOneThatContainsVersionsOrDomainSpecificName
{
   ...
}

public class MyName = LongClassNameOrOneThatContainsVersionOrDomainSpecificName;

mas não compilará.


Exemplo

Nota Este exemplo é fornecido apenas por conveniência. Não tente resolver esse problema específico sugerindo alterar o design de todo o sistema. A presença, ou falta, deste exemplo não altera a pergunta original.

Alguns códigos existentes dependem da presença de uma classe estática:

public static class ColorScheme
{
   ...
}

Este esquema de cores é o esquema de cores do Outlook 2003. quero apresentar um esquema de cores do Outlook 2007, mantendo o esquema de cores do Outlook 2003:

public static class Outlook2003ColorScheme
{
   ...
}

public static class Outlook2007ColorScheme
{
   ...
}

Mas ainda sou confrontado com o fato de que o código depende da presença de uma classe estática chamada ColorScheme. Meu primeiro pensamento foi criar uma ColorSchemeclasse que herdarei de Outlook2003ou Outlook2007:

public static class ColorScheme : Outlook2007ColorScheme
{
}

mas você não pode herdar de uma classe estática.

Meu próximo pensamento foi criar a ColorSchemeclasse estática , mas fazer Outlook2003ColorSchemee as Outlook2007ColorSchemeclasses não estáticas. Então, uma variável estática na ColorSchemeclasse estática pode apontar para qualquer esquema de cores "verdadeiro":

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

private class CustomColorScheme 
{ 
   ...
}

private class Outlook2008ColorScheme : CustomColorScheme 
{
    ...
}

private class Outlook2003ColorScheme : CustomColorScheme 
{
   ...
}

mas isso exigiria que eu convertesse uma classe composta inteiramente de cores estáticas somente leitura em propriedades substituíveis e, em seguida, minha ColorSchemeclasse precisaria ter os 30 getters de propriedade diferentes transformados no objeto contido.

Isso é muita digitação.

Então, meu próximo pensamento foi criar um alias para a classe:

public static ColorScheme = Outlook2007ColorScheme;

Mas isso não compila.

Como posso criar um alias para uma classe estática com outro nome?


Atualização: Alguém pode adicionar a resposta "Você não pode fazer isso em C #" , para que eu possa marcá-la como uma resposta aceita. Qualquer pessoa que deseje a resposta para a mesma pergunta encontrará esta pergunta, a resposta aceita e uma série de soluções alternativas que podem ou não ser úteis.

Eu só quero encerrar esta questão.

Ian Boyd
fonte
Você também pode aceitar a resposta de Chris, mesmo que não queira implementá-la
devio
2
Não é a resposta, é uma solução alternativa. A resposta é que você não pode - pelo menos até que alguém chegue e poste a sintaxe real para fazer isso.
Ian Boyd
1
Para qualquer um que vier aqui, a resposta aceita está incorreta, pois o comentário com a melhor classificação funciona bem nos projetos VS 2010 e VS 2017 c # nos quais estou trabalhando. O namespace totalmente qualificado deve ser usado para especificar a classe ao configurar o alias, mas uma vez configurado, o alias funciona dentro de seu escopo definido.
J-Americano de
Tive que ler a resposta de Ian e seus comentários detalhadamente antes de entender o que ele estava procurando. Ele deseja declarar um alias de classe em um lugar , em vez de ter que adicioná-lo ao início de cada arquivo que faz referência à classe. Não conheço nenhuma linguagem fortemente tipada que suporte isso. (Se alguém conhece tal linguagem, gostaria de saber.) Editei o título para deixar isso mais claro.
Toolmaker Steve
BTW, para qualquer um que está tentando fazer algo semelhante: se essas são classes que você está definindo, a abordagem C # é definir um interface, que todas as suas classes implementam. Conforme mencionado na resposta do chills42 . Você pode então definir um "serviço" ou "fábrica" ​​que retorna um objeto que implementa aquela interface, dependendo das circunstâncias atuais (por exemplo, plataforma / SO) ou em um arquivo de configuração.
Toolmaker Steve

Respostas:

129

Você não pode . A próxima melhor coisa que você pode fazer é ter usingdeclarações nos arquivos que usam a classe.

Por exemplo, você pode reescrever o código dependente usando um alias de importação (como um quase typedefsubstituto):

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

Infelizmente, isso precisa entrar em cada escopo / arquivo que usa o nome.

Portanto, não sei se isso é prático no seu caso.

Konrad Rudolph
fonte
9
Se pudesse ir no início do arquivo que continha a classe original: seria ótimo. Mas o usingdeve ser adicionado a todo código quebrado. E também nega o valor de ter um único alias, que me permite mudar todos os usuários da ColorSchemeclasse existente para usar uma nova classe - sem alterações. Em outras palavras: eu quero atribuir o alias da ColorSchemeclasse a outra classe.
Ian Boyd,
Existe uma maneira de conseguir o mesmo e propagar o alias com herança. ou seja, todas as classes que estendem MyClass serão capazes de usar ColorScheme em vez de the.Fully.Qualified ... ColorScheme apenas adicionando a instrução using no arquivo de origem MyClass?
Florian Burel
Bem, foi muito prático para o meu caso. Finalmente C # irá parar de desenhar meus caminhos de arquivo.
ElDoRado1239
25

Você pode criar um alias para sua classe adicionando esta linha de código:

using Outlook2007ColorScheme = YourNameSpace.ColorScheme;
Mohammedn
fonte
O nome 'ColorScheme' não existe no contexto atual
Ian Boyd
7
você precisa de Fully.Qualified.Namespace.Of.ColorScheme
Jamie Pate
Achei que em C # só poderia criar nomes de namespaces (não classes) dessa forma, enquanto em VB.Net você pode criar nomes de namespaces ou classes usando Imports. Estou errado?
Nick
Você não precisa de um nome totalmente qualificado se você colocar uma usingdiretiva dentro de seu namespace, por exemplo, quando você precisa de um apelido de sua própria classe.
Elvedin Hamzagic de
12

Você deseja um ( Factory | Singleton ), dependendo de seus requisitos. A premissa é fazer com que o código do cliente não precise saber qual esquema de cores está recebendo. Se o esquema de cores deve ser amplo, um singleton deve servir. Se você pode usar um esquema diferente em circunstâncias diferentes, um padrão de fábrica é provavelmente o caminho a percorrer. De qualquer forma, quando o esquema de cores precisa ser alterado, o código só precisa ser alterado em um lugar.

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
fonte
Isso parece menos uma fábrica e mais uma tentativa fraca de um padrão único. Uma fábrica teria mais chances de parametrizar o método de criação; você teria algo mais como: public static ColorScheme GetColorScheme (descritor de string);
OwenP
Verdade - a ideia básica é garantir que, quando o Office 2012 for lançado, o código só precisará ser alterado em um lugar.
Chris Marasti-Georg,
1
Isso definitivamente funciona, mas certamente é uma solução corporativa para um problema simples.
Ian Boyd
11

Você não pode criar um alias para um nome de classe em C #.

Existem coisas que você pode fazer que não são o alias de um nome de classe em C #.

Mas, para responder à pergunta original: você não pode criar um alias para um nome de classe em C #.


Update: As pessoas estão confusas porque usingnão funciona. Exemplo:

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 tudo funciona. Agora eu quero criar uma nova classe e um alias ColorScheme para ela (de modo que nenhum código precise ser modificado ):

ColorScheme.cs

using ColorScheme = Outlook2007ColorScheme;

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

Ohh, sinto muito. Este código não compila:

insira a descrição da imagem aqui

Minha pergunta era como criar um alias para uma classe em C #. Isso não pode ser feito. Existem coisas que posso fazer que não são o alias de um nome de classe em C #:

  • altere todos os que dependem ColorSchemepara using ColorScheme(solução alternativa de alteração de código porque não consigo apelido)
  • mude todos os que dependem ColorSchemepara usar um padrão de fábrica para uma classe polimórfica ou interface (solução alternativa de mudança de código porque eu não consigo apelido)

Mas essas soluções alternativas envolvem quebrar o código existente: não é uma opção.

Se as pessoas dependem da presença de uma ColorSchemeclasse, tenho que realmente copiar / colar uma ColorSchemeclasse.

Em outras palavras: não posso criar um alias para o nome de uma classe em C #.

Isso contrasta com outras linguagens orientadas a objetos, onde eu poderia definir o alias:

ColorScheme = Outlook2007ColorScheme

e eu estaria pronto.

Ian Boyd
fonte
21
Você absolutamente pode criar um alias para um nome de classe em C #. "usando <alias_name> = <fully_qualified_name>;"
clemahieu
7
Como @clemahieu disse, você absolutamente pode criar um alias para o nome de uma classe, basta usar o nome totalmente qualificado. Além disso, se você está atribuindo alias a uma classe genérica, pode ser necessário adicionar o qualificador de classe genérica. Por exemplo: using ShortName = MyNamespace.SubNamespace.GenericClass <MyType>;
Dan Morphis,
11
Downvote - você declarou "Você não pode usar o apelido de um nome de classe em C #." Você pode. O que você não pode fazer é criar um apelido para uma classe da maneira que deseja - o que é um requisito bastante justificado, mas sua afirmação está incorreta.
Tom W
8
Como vários pôsteres indicaram, ter que usar o nome qualificado de forma alguma proíbe o aliasing. Você pode criar um alias para a classe. Você só precisa usar o nome totalmente qualificado para fazer isso. Você pode achar isso inconveniente, mas não torna verdadeira a afirmação 'Você não pode usar o apelido de um nome de classe em C #'. Talvez a maneira como o aliasing funciona em C # seja diferente do que você esperava. Tudo bem - se for esse o caso, diga isso. Mas você pode criar um alias para um nome de classe em C # porque a especificação afirma que você pode fazer isso, de acordo com a definição que ela fornece.
Tom W
5
Gosto de como nós, programadores, faremos nossas declarações nas entrelinhas. O que Ian está realmente dizendo é que o C # é burro e quebrado porque não pode fazer uma coisa básica simples que qualquer pessoa gostaria de fazer e deveria ser capaz de fazer. Ele está correto - independentemente de uma semântica específica deixar você feliz ou não.
IQpierce
10

tente isto:

using ColorScheme=[fully qualified].Outlook2007ColorScheme
Dpurrington
fonte
O nome 'ColorScheme' não existe no contexto atual
Ian Boyd
2
você precisa de Fully.Qualified.Namespace.Of.ColorScheme
Jamie Pate
6

Estou adicionando este comentário para usuários que acham isso muito depois de OP aceitar sua "resposta". Aliasing em C # funciona especificando o nome da classe usando seu namespace totalmente qualificado. Um definido, o nome do alias pode ser usado dentro de seu escopo. Exemplo.

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
  }

}

Pedimos desculpas pelo código digitado rapidamente, mas espero que ele explique como isso deve ser implementado para que os usuários não se enganem pensando que isso não pode ser feito em C #.

J-Americano
fonte
Isso seria ainda mais clara se você mostrou a declaração de outra classe: namespace Fully.Qualified.Namespace{ public class Example {... public void DoStuff(){... }... } }.
Toolmaker Steve
1
Para ser claro, isso é diferente do que Ian está procurando. Ian tem uma situação em que ele não pode (ou não quer) alterar os arquivos de origem que se referem a uma classe. Ele quer uma maneira de fazer uma mudança em apenas um lugar em seu aplicativo ou biblioteca , resultando no que parece ser uma classe com o nome desejado, que todos os outros códigos podem usar [sem ter que adicionar essa instrução "using" a fontes múltiplas arquivos - por exemplo, essa fonte pode não estar disponível para alteração].
Toolmaker Steve
4

Criar apelidos da maneira que você gostaria de fazer não funcionará em C #. Isso ocorre porque o aliasing é feito por meio da usingdiretiva, que é limitada ao arquivo / espaço de nomes em questão. Se você tiver 50 arquivos que usam o nome da classe antiga, isso significará 50 lugares para atualizar.

Dito isso, acho que há uma solução fácil para fazer a alteração do código o mínimo possível. Faça da ColorSchemeclasse uma fachada para suas chamadas para as classes reais com a implementação e use o usingnesse arquivo para determinar qual ColorSchemevocê usa.

Em outras palavras, faça o seguinte:

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

Então, em seu code-behind, não mude nada:

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

Você pode então atualizar os valores de ColorSchemeatualizando uma linha de código ( using CurrentColorScheme = Outlook2008ColorScheme;).

Algumas preocupações aqui:

  • Cada novo método ou definição de propriedade precisará então ser adicionado em dois lugares, para a ColorSchemeclasse e para a Outlook2007ColorSchemeclasse. Isso é um trabalho extra, mas se for um código legado verdadeiro, não deve ser uma ocorrência frequente. Como um bônus, o código ColorSchemeé tão simples que qualquer bug possível é muito óbvio.
  • Esse uso de classes estáticas não parece natural para mim; Eu provavelmente tentaria refatorar o código legado para fazer isso de maneira diferente, mas também entendo que sua situação pode não permitir isso.
  • Se você já tem uma ColorSchemeclasse que está substituindo, esta abordagem e qualquer outra pode ser um problema. Aconselho que você renomeie essa classe para algo como ColorSchemeOlde, em seguida, acesse-a por meio de using CurrentColorScheme = ColorSchemeOld;.
Timothy
fonte
3

Suponho que você sempre pode herdar da classe base sem adicionar nada

public class Child : MyReallyReallyLongNamedClass {}

ATUALIZAR

Mas se você tiver a capacidade de refatorar o classpróprio: Um nome de classe geralmente é desnecessariamente longo devido à falta de namespaces.

Se você vê casos como ApiLoginUser, DataBaseUser, WebPortalLoginUser, é geralmente indicação de falta de namespacedevido o medo de que o nome Userconflito força.

Neste caso, entretanto, você pode usar um namespaceapelido , como foi apontado nas postagens acima

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

Observe como os classnomes são todos User, mas em namespaces diferentes . Citando PEP-20: Zen de Python :

Os namespaces são uma ótima ideia - vamos fazer mais disso!

Espero que isto ajude

percebus
fonte
2
sempre, a menos que você não possa: por exemplo, classe selada
mikus
mas isso não funcionará em muitos casos. por exemplo, public class MyList: List {} - se você tentar mais tarde MyList xyz = something.ToList (); você vai ficar preso.
Offler de
@Offler Você poderia (e provavelmente deveria) recorrer a qualquer uma das newpalavras-chave para esses métodos ou até mesmo criar seus próprios ExtensionMethods, certo? Em qualquer caso, é minha opinião forte que você deve sempre usar classes de coleção vanilla (ou seja, Dicionário, Lista, IEnumerable, IQueryable, etc.) com Modelos / ViewModels / POCOs personalizados. Como afirma
Mvc
@percebus não funciona em todos os casos. Tento transformar o código antigo em que as partes usam uma API que não é mais compatível para uma mais recente. o código de transformação durável será alterado por outros e ainda deve ser executável - portanto, ambos devem ser utilizáveis ​​agora. converter coisas acima de 700.000 LOC (sem comentários) e ainda permitir que sejam executáveis ​​seria mais fácil, se um alias de estilo c ++ fosse possível - e você só precisa de um lugar em um arquivo para substituir uma classe de alias com a implementação de qualquer um deles.
Offler
RE-POST for EDIT @Offler Para o que você está descrevendo, você precisa de algo como um Factory com interfaces. IColorScheme oColorScheme = ColorSchemeFactory.Create(); Além disso, você pode querer dar uma olhada em Injeção de dependência
percebus
2

É possível mudar para uma interface?

Talvez você possa criar uma IColorSchemeinterface que todas as classes implementem?

Isso funcionaria bem com o padrão de fábrica mostrado por Chris Marasti-Georg

calafrios 42
fonte
Pode ser, mas não vou perder mais tempo com isso, em vez de renomear a classe que é o esquema de cores "atual" a ser usado.
Ian Boyd
0

É uma resposta parcial muito tardia - mas se você definir a mesma classe 'ColorScheme', no mesmo namespace 'Outlook', mas em assemblies separados, um chamado Outlook2003 e o outro Outlook2007, então tudo que você precisa fazer é referenciar o assembly apropriado .

Mark Farmiloe
fonte