Sou fã de métodos de extensão em C #, mas não tive sucesso ao adicionar um método de extensão a uma classe estática, como o Console.
Por exemplo, se eu quiser adicionar uma extensão ao console, chamada 'WriteBlueLine', para que eu possa:
Console.WriteBlueLine("This text is blue");
Eu tentei isso adicionando um método estático público local, com o Console como um parâmetro 'this' ... mas não há dados!
public static class Helpers {
public static void WriteBlueLine(this Console c, string text)
{
Console.ForegroundColor = ConsoleColor.Blue;
Console.WriteLine(text);
Console.ResetColor();
}
}
Isso não adicionou um método 'WriteBlueLine' ao Console ... estou fazendo errado? Ou pedindo o impossível?
c#
static
extension-methods
Leon Bambrick
fonte
fonte
Helpers.WriteBlueLine(null, "Hi");
:)Respostas:
Não. Os métodos de extensão requerem uma variável de instância (valor) para um objeto. No entanto, você pode escrever um invólucro estático em torno da
ConfigurationManager
interface. Se você implementar o wrapper, não precisará de um método de extensão, pois você pode simplesmente adicionar o método diretamente.fonte
Você pode adicionar extensões estáticas às classes em c #? Não, mas você pode fazer isso:
Aqui está como isso funciona. Embora você não possa tecnicamente escrever métodos de extensão estáticos, esse código explora uma brecha nos métodos de extensão. Essa brecha é que você pode chamar métodos de extensão em objetos nulos sem obter a exceção nula (a menos que você acesse algo via @this).
Então, aqui está como você usaria isso:
Agora, por que escolhi chamar o construtor padrão como exemplo e AND por que não retornei o novo T () no primeiro trecho de código sem fazer todo esse lixo de expressão? Bem, hoje é seu dia de sorte, porque você recebe um 2fer. Como qualquer desenvolvedor .NET avançado sabe, o novo T () é lento porque gera uma chamada para System.Activator que usa reflexão para obter o construtor padrão antes de chamá-lo. Maldito seja, Microsoft! No entanto, meu código chama o construtor padrão do objeto diretamente.
Extensões estáticas seriam melhores do que isso, mas tempos desesperados exigem medidas desesperadas.
fonte
XConsole
,ConsoleHelper
e assim por diante.(null as DataSet).Create();
poderia serdefault(DataSet).Create();
.Não é possível.
E sim, acho que a MS cometeu um erro aqui.
Sua decisão não faz sentido e força os programadores a escrever (como descrito acima) uma classe de invólucro sem sentido.
Aqui está um bom exemplo: Tentando estender a classe estática de teste de Unidade MS Assert: Quero mais 1 método Assert
AreEqual(x1,x2)
.A única maneira de fazer isso é apontar para diferentes classes ou escrever um wrapper em torno de centenas de diferentes métodos Assert. Por quê!?
Se a decisão foi tomada para permitir extensões de instâncias, não vejo razão lógica para não permitir extensões estáticas. Os argumentos sobre o seccionamento de bibliotecas não se sustentam quando as instâncias podem ser estendidas.
fonte
Assert.Throws
com a resposta stackoverflow.com/questions/113395/…Eu me deparei com esse tópico enquanto tentava encontrar uma resposta para a mesma pergunta que o OP tinha. Não encontrei a resposta que queria, mas acabei fazendo isso.
E eu uso assim:
fonte
Talvez você possa adicionar uma classe estática com seu namespace personalizado e o mesmo nome de classe:
fonte
A partir do C # 7, isso não é suportado. No entanto, há discussões sobre a integração de algo assim no C # 8 e propostas que valem a pena apoiar .
fonte
Não. As definições de método de extensão exigem uma instância do tipo que você está estendendo. É lamentável; Não sei por que é necessário ...
fonte
Quanto aos métodos de extensão, os próprios métodos de extensão são estáticos; mas eles são chamados como se fossem métodos de instância. Como uma classe estática não é instanciada, você nunca teria uma instância da classe para invocar um método de extensão. Por esse motivo, o compilador não permite que métodos de extensão sejam definidos para classes estáticas.
Obnoxious escreveu: "Como qualquer desenvolvedor .NET avançado sabe, o novo T () é lento porque gera uma chamada para System.Activator que usa reflexão para obter o construtor padrão antes de chamá-lo".
New () é compilado na instrução IL "newobj" se o tipo for conhecido no momento da compilação. Newobj usa um construtor para invocação direta. Chamadas para System.Activator.CreateInstance () compilam a instrução "call" de IL para chamar System.Activator.CreateInstance (). New () quando usado em tipos genéricos resultará em uma chamada para System.Activator.CreateInstance (). O post do Sr. Obnóxio não era claro sobre este ponto ... e bem, detestável.
Este código:
produz este IL:
fonte
Você não pode adicionar estática métodos a um tipo. Você só pode adicionar métodos (pseudo-) de instância a uma instância de um tipo.
O objetivo do
this
modificador é dizer ao compilador C # para passar a instância no lado esquerdo do.
como o primeiro parâmetro do método static / extension.No caso de adicionar métodos estáticos a um tipo, não há instância a ser transmitida para o primeiro parâmetro.
fonte
Tentei fazer isso com o System.Environment quando estava aprendendo métodos de extensão e não obtive sucesso. O motivo é, como outros mencionam, porque os métodos de extensão requerem uma instância da classe.
fonte
Não é possível escrever um método de extensão, no entanto, é possível imitar o comportamento que você está solicitando.
Isso permitirá que você chame Console.WriteBlueLine (fooText) em outras classes. Se as outras classes quiserem acessar as outras funções estáticas do Console, elas deverão ser explicitamente referenciadas através de seu espaço para nome.
Você sempre pode adicionar todos os métodos à classe de substituição se desejar tê-los em um só lugar.
Então você teria algo como
Isso forneceria o tipo de comportamento que você está procurando.
* Nota O console precisará ser adicionado através do espaço para nome em que você o colocou.
fonte
sim, em um sentido limitado.
Isso funciona, mas o console não, porque é estático.
Isso funciona porque contanto que não esteja no mesmo espaço para nome. O problema é que você precisa escrever um método estático de proxy para cada método que o System.Console possui. Não é necessariamente uma coisa ruim, pois você pode adicionar algo como isto:
ou
O modo como funciona é que você conecta algo ao WriteLine padrão. Pode ser uma contagem de linhas ou um filtro de palavras incorretas ou qualquer outra coisa. Sempre que você especificar o Console no seu espaço para nome, diga WebProject1 e importe o espaço para nome System, WebProject1.Console será escolhido sobre System.Console como padrão para as classes no espaço para nome WebProject1. Portanto, esse código transformará todas as chamadas Console.WriteLine em azul, na medida em que você nunca especificou System.Console.WriteLine.
fonte
O seguinte foi rejeitado como uma edição da resposta de tvanfosson. Fui convidado a contribuir como minha própria resposta. Usei sua sugestão e finalizei a implementação de um
ConfigurationManager
wrapper. Em princípio, simplesmente preenchi a...
resposta de tvanfosson.fonte
Você pode usar uma conversão em null para fazê-lo funcionar.
A extensão:
Seu tipo:
fonte
Você pode fazer isso se estiver disposto a "frig" um pouco, criando uma variável da classe estática e atribuindo-a a null. No entanto, esse método não estaria disponível para chamadas estáticas na classe, portanto, não tenho certeza de quanto uso seria:
fonte