Recursos ocultos do c #? [fechadas]


1475

Isso veio à minha mente depois que aprendi o seguinte com esta pergunta :

where T : struct

Nós, desenvolvedores de C #, todos sabemos o básico de C #. Refiro-me a declarações, condicionais, loops, operadores, etc.

Alguns de nós até dominam coisas como Genéricos , tipos anônimos , lambdas , LINQ , ...

Mas quais são os recursos ou truques mais ocultos do C # que mesmo os fãs, viciados e especialistas em C # mal conhecem?

Aqui estão os recursos revelados até agora:


Palavras-chave

Atributos

Sintaxe

  • ??(coalesce nulls) operator por kokos
  • Bandeiras de número por Nick Berardi
  • where T:newpor Lars Mæhlum
  • Genéricos implícitos de Keith
  • Lambdas de um parâmetro por Keith
  • Auto propriedades por Keith
  • Alias ​​de namespace de Keith
  • Literais de string verbais com @ by Patrick
  • enumvalores por lfoust
  • @variablenames por marxidad
  • eventoperadores por marxidad
  • Formatar colchetes por Portman
  • Modificadores de acessibilidade de acessador de propriedade por xanadont
  • Operador condicional (ternário) ( ?:) por JasonS
  • checkede uncheckedoperadores por Binoj Antony
  • implicit and explicitoperadores de Flory

Características da linguagem

Recursos do Visual Studio

Estrutura

Métodos e propriedades

dicas e truques

  • Bom método para manipuladores de eventos por Andreas HR Nilsson
  • Comparações em maiúsculas de John
  • Acesse tipos anônimos sem reflexão por dp
  • Uma maneira rápida de instanciar preguiçosamente as propriedades de coleção de Will
  • Funções inline anônimas do tipo JavaScript por roosteronacid

De outros

Respostas:


752

Isso não é C # por si só, mas não vi ninguém que realmente use System.IO.Path.Combine()na medida em que deveria. De fato, toda a classe Path é realmente útil, mas ninguém a usa!

Estou disposto a apostar que todo aplicativo de produção tem o seguinte código, mesmo que não deva:

string path = dir + "\\" + fileName;

584

lambdas e inferência de tipo são subestimadas. Os lambdas podem ter várias instruções e dobram como um objeto delegado compatível automaticamente (apenas verifique se a assinatura corresponde) como em:

Console.CancelKeyPress +=
    (sender, e) => {
        Console.WriteLine("CTRL+C detected!\n");
        e.Cancel = true;
    };

Observe que eu não tenho new CancellationEventHandlernem preciso especificar tipos de sendere e, eles são inferíveis a partir do evento. É por isso que isso é menos complicado para escrever o todo, o delegate (blah blah)que também exige que você especifique tipos de parâmetros.

Os lambdas não precisam retornar nada e a inferência de tipo é extremamente poderosa em um contexto como este.

E, BTW, você sempre pode retornar Lambdas que fazem Lambdas no sentido de programação funcional. Por exemplo, aqui está uma lambda que cria uma lambda que lida com um evento Button.Click:

Func<int, int, EventHandler> makeHandler =
    (dx, dy) => (sender, e) => {
        var btn = (Button) sender;
        btn.Top += dy;
        btn.Left += dx;
    };

btnUp.Click += makeHandler(0, -1);
btnDown.Click += makeHandler(0, 1);
btnLeft.Click += makeHandler(-1, 0);
btnRight.Click += makeHandler(1, 0);

Observe o encadeamento: (dx, dy) => (sender, e) =>

Agora é por isso que estou feliz por ter participado da aula de programação funcional :-)

Além dos ponteiros em C, acho que é outra coisa fundamental que você deve aprender :-)


528

De Rick Strahl :

Você pode encadear o ?? operador para que você possa fazer várias comparações nulas.

string result = value1 ?? value2 ?? value3 ?? String.Empty;

454

Genéricos com alias:

using ASimpleName = Dictionary<string, Dictionary<string, List<string>>>;

Ele permite que você use ASimpleName, em vez de Dictionary<string, Dictionary<string, List<string>>>.

Use-o quando você usaria a mesma coisa grande e complexa genérica em muitos lugares.


438

Do CLR via C # :

Ao normalizar seqüências de caracteres, é altamente recomendável usar ToUpperInvariant em vez de ToLowerInvariant porque a Microsoft otimizou o código para realizar comparações em maiúsculas .

Lembro-me de uma vez em que meu colega de trabalho sempre mudava as cordas para maiúsculas antes de comparar. Eu sempre me perguntei por que ele faz isso porque sinto que é mais "natural" converter primeiro em minúsculas. Depois de ler o livro agora eu sei o porquê.


254
Quando você "converte uma string em maiúscula", cria um segundo objeto de string temporário. Eu pensei que esse tipo de comparação não era preferido, que a melhor maneira era: String.Equals (stringA, stringB, StringComparison.CurrentCultureIgnoreCase) whcih não cria essa string descartável.
Anthony

32
Que tipo de otimização você pode executar ao comparar cadeias de letras maiúsculas que não podem ser feitas em letras minúsculas? Não entendo por que um seria mais ideal que o outro.
Parappa

36
A conversão em maiúsculas em vez de minúsculas também pode impedir o comportamento incorreto em determinadas culturas. Por exemplo, em turco, o mapa de dois i minúsculos para o mesmo I. maiúsculo do Google. Google "i turco" para obter mais detalhes.
194 Neil

34
Tentei fazer benchmarking ToUpperInvariant vs ToLowerInvariant. Não consigo encontrar nenhuma diferença em seu desempenho no .NET 2.0 ou 3.5. Certamente, nada que justifique "recomendar altamente" o uso de um sobre o outro.
Rasmus Faber

19
É preferível ToUpperInvariant porque faz com que todos os caracteres sejam de ida e volta. Consulte msdn.microsoft.com/en-us/library/bb386042.aspx . Para comparações, escreva"a".Equals("A", StringComparison.OrdinalIgnoreCase)
SLaks 4/09/09

408

Meu truque favorito é usar o operador de coalescência nula e parênteses para instanciar automaticamente coleções para mim.

private IList<Foo> _foo;

public IList<Foo> ListOfFoo 
    { get { return _foo ?? (_foo = new List<Foo>()); } }

23
Você não acha difícil de ler?
Riri

72
É um pouco difícil de ler para o novato, inexperiente. Mas é compacto e contém alguns padrões e recursos de linguagem que o programador deve conhecer e entender. Portanto, embora seja difícil a princípio, ele oferece o benefício de ser um motivo para aprender.

38
A instanciação preguiçosa é um pouco imperícia porque é uma má escolha do homem para evitar pensar em invariantes de classe. Ele também tem problemas de simultaneidade.
John Leidegren

17
Sempre fui informado de que isso é uma má prática, que chamar uma propriedade não deve fazer algo como tal. Se você tivesse um conjunto lá e definisse o valor como nulo, seria muito estranho para alguém usar sua API.
7262 Ian

8
@Joel, exceto que definir ListOfFoo como null não faz parte do contrato da classe nem é uma boa prática. É por isso que não há um levantador. É também por isso que ListOfFoo tem a garantia de retornar uma coleção e nunca um valor nulo. É apenas uma queixa muito estranha de que, se você fizer duas coisas ruins (faça um levantador e defina uma coleção como nula), isso resultará em uma expectativa errada. Eu não sugeriria fazer Environment.Exit () no getter, também. Mas isso também não tem nada a ver com esta resposta.

315

Evite verificar manipuladores de eventos nulos

Adicionar um representante vazio aos eventos na declaração, suprimindo a necessidade de sempre verificar se o evento é nulo antes de chamá-lo de impressionante. Exemplo:

public delegate void MyClickHandler(object sender, string myValue);
public event MyClickHandler Click = delegate {}; // add empty delegate!

Deixe você fazer isso

public void DoSomething()
{
    Click(this, "foo");
}

Em vez disso

public void DoSomething()
{
    // Unnecessary!
    MyClickHandler click = Click;
    if (click != null) // Unnecessary! 
    {
        click(this, "foo");
    }
}

Por favor, veja também esta discussão relacionada e esta postagem de Eric Lippert no blog sobre este tópico (e possíveis desvantagens).


87
Acredito que um problema aparecerá se você confiar nessa técnica e precisar serializar a classe. Você eliminará o evento e, na desserialização, obterá uma NullRefference ..... É mais seguro.
Sirrocco

16
você ainda pode definir seu manipulador de eventos como nulo, para obter uma referência nula e ainda ter uma condição de corrida.
Robert Paulson

64
Um teste rápido de perfil mostra que o manipulador de eventos com assinatura fictícia sem teste nulo leva aproximadamente duas vezes o tempo do manipulador de eventos com inscrição nula com teste nulo. O manipulador de eventos multicast sem teste nulo leva cerca de 3,5 vezes o tempo do manipulador de eventos singlecast com teste nulo.
P papai

54
Isso evita a necessidade de uma verificação nula, sempre tendo sempre um auto-assinante. Mesmo como um evento vazio, isso carrega uma sobrecarga que você não deseja. Se não houver assinantes, você não deseja disparar o evento, nem sempre ative um evento fictício vazio primeiro. Eu consideraria esse código incorreto.
Keith

56
Essa é uma sugestão terrível, pelas razões dos comentários acima. Se você deve fazer com que seu código pareça "limpo", use um método de extensão para verificar se há nulo e chame o evento. Alguém com privilégios de modificação deve adicionar definitivamente os contras a esta resposta.
Greg

305

Tudo o resto, além de

1) genéricos implícitos (por que apenas nos métodos e não nas classes?)

void GenericMethod<T>( T input ) { ... }

//Infer type, so
GenericMethod<int>(23); //You don't need the <>.
GenericMethod(23);      //Is enough.

2) lambdas simples com um parâmetro:

x => x.ToString() //simplify so many calls

3) tipos e inicializadores anônimos:

//Duck-typed: works with any .Add method.
var colours = new Dictionary<string, string> {
    { "red", "#ff0000" },
    { "green", "#00ff00" },
    { "blue", "#0000ff" }
};

int[] arrayOfInt = { 1, 2, 3, 4, 5 };

Outro:

4) As propriedades automáticas podem ter escopos diferentes:

public int MyId { get; private set; }

Obrigado @pzycoman por me lembrar:

5) Aliases de namespace (não que você precise dessa distinção específica):

using web = System.Web.UI.WebControls;
using win = System.Windows.Forms;

web::Control aWebControl = new web::Control();
win::Control aFormControl = new win::Control();

14
em # 3 você pode fazer Enumerable.Range (1,5)
Echostorm 7/08

18
Eu acho que você foi capaz de inicializar matrizes com int [] nums = {1,2,3}; desde 1.0 :) nem precisa da palavra
Lucas

13
também lambda sem parâmetros () => DoSomething ();
Pablo Retyk

5
Eu usei os dois {get; conjunto interno; } e pegue; conjunto protegido; }, então esse padrão é consistente.
519 Keith

7
@Kirk Broadhurst - você está certo - new web.Control()também funcionaria neste exemplo. A ::sintaxe obriga a tratar o prefixo como um alias de espaço para nome, para que você possa ter uma classe chamada webe a web::Controlsintaxe ainda funcione, enquanto a web.Controlsintaxe não saberá se deve verificar a classe ou o espaço para nome. Por isso, costumo usar sempre ::quando faço alias de namespace.
Keith

286

Eu não conhecia a palavra-chave "as" por um bom tempo.

MyClass myObject = (MyClass) obj;

vs

MyClass myObject = obj as MyClass;

O segundo retornará null se obj não for um MyClass, em vez de lançar uma exceção de conversão de classe.


42
Mas não exagere. Muitas pessoas parecem usar isso porque preferem a sintaxe, apesar de quererem a semântica de um (ToType) x.
21968 Scott Langham

4
Não acredito que ofereça melhor desempenho. Você definiu o perfil? (Obviamente que ele faz quando o elenco falhar ... mas quando você usa (MyClass) fundido, as falhas são excepcionais .. e extremamente raro (se acontecer a todos), por isso não faz diferença.
Scott Langham

7
Isso é apenas mais eficiente se o caso usual é o elenco falhando. Caso contrário, o objeto de conversão direta (tipo) é mais rápido. Leva mais tempo para uma conversão direta lançar uma exceção do que retornar nulo.
Spence

15
Nas mesmas linhas da palavra-chave "as" ... a palavra-chave "is" é igualmente útil.
Dkpatt 07/05/09

28
Você pode abusar e ter uma NullReferenceException no caminho mais tarde, quando você poderia ter tido uma InvalidCastException anteriormente.
Andrei Rînea 02/09/09

262

Duas coisas de que gosto são as propriedades Automáticas, para que você possa reduzir ainda mais seu código:

private string _name;
public string Name
{
    get
    {
        return _name;
    }
    set
    {
        _name = value;
    }
}

torna-se

public string Name { get; set;}

Também inicializadores de objetos:

Employee emp = new Employee();
emp.Name = "John Smith";
emp.StartDate = DateTime.Now();

torna-se

Employee emp = new Employee {Name="John Smith", StartDate=DateTime.Now()}

6
Deve-se observar que as propriedades automáticas são um recurso exclusivo do C # 3.0?
Jared Updike

21
As propriedades automáticas foram introduzidas com o compilador 3.0. Mas como o compilador pode ser configurado para gerar o código 2.0, eles funcionam bem. Apenas não tente compilar o código 2.0 com propriedades automáticas em um compilador mais antigo!
21009 Joshua Shannon

74
Algo que muitas pessoas não percebem é que get e set podem ter acessibilidade diferente, por exemplo: public string Name {get; conjunto privado;} #
Nader Shirazie

7
O único problema com as propriedades automáticas é que não parece possível fornecer um valor de inicialização padrão.
Stein Åsmul 12/09/09

7
@ ANeves: não, não é. A partir dessa página: Um DefaultValueAttribute não fará com que um membro seja inicializado automaticamente com o valor do atributo. Você deve definir o valor inicial no seu código. [DefaultValue]é usado para o designer, para que ele saiba se deve mostrar uma propriedade em negrito (ou seja, não padrão).
precisa

255

A palavra-chave 'padrão' em tipos genéricos:

T t = default(T);

resulta em 'null' se T for um tipo de referência e 0 se for um int, false se for um booleano, etc.


4
Plus: tipo? como um atalho para Nullable <type>. padrão (int) == 0, mas padrão (int?) == nulo.
sol


221

O @ diz ao compilador para ignorar qualquer caractere de escape em uma string.

Só queria esclarecer este ... ele não diz para ignorar os caracteres de escape, na verdade, diz ao compilador para interpretar a string como um literal.

Se você tem

string s = @"cat
             dog
             fish"

ele realmente será impresso como (observe que ele inclui o espaço em branco usado para o recuo):

cat
             dog
             fish

a string não incluiria todos os espaços que você usou para recuar?
andy

18
Sim, isso é chamado de string literal.
Joan Venge

4
Seria mais claro se a saída mostrasse os espaços que também seriam impressos. No momento, parece que os novos caracteres das linhas são impressos, mas os espaços são ignorados.
aleemb

Muito útil para escapar de expressões regulares e longas consultas SQL.
precisa saber é o seguinte

Também mapeia {{para {e }}para }torná-lo útil string.Format().
Ferruccio

220

Acho que um dos recursos mais subestimados e menos conhecidos do C # (.NET 3.5) são as Árvores de Expressão , especialmente quando combinadas com os Genéricos e Lambdas. Essa é uma abordagem para criação de API que bibliotecas mais recentes, como NInject e Moq, estão usando.

Por exemplo, digamos que eu quero registrar um método com uma API e que a API precise obter o nome do método

Dada esta classe:

public class MyClass
{
     public void SomeMethod() { /* Do Something */ }
}

Antes, era muito comum ver os desenvolvedores fazerem isso com strings e tipos (ou qualquer outra coisa amplamente baseada em strings):

RegisterMethod(typeof(MyClass), "SomeMethod");

Bem, isso é péssimo por causa da falta de digitação forte. E se eu renomear "SomeMethod"? Agora, na versão 3.5, no entanto, posso fazer isso de uma maneira fortemente tipada:

RegisterMethod<MyClass>(cl => cl.SomeMethod());

Na qual a classe RegisterMethod usa Expression<Action<T>>assim:

void RegisterMethod<T>(Expression<Action<T>> action) where T : class
{
    var expression = (action.Body as MethodCallExpression);

    if (expression != null)
    {
        // TODO: Register method
        Console.WriteLine(expression.Method.Name);
    }
}

Esse é um dos grandes motivos pelos quais estou apaixonado por Lambdas e Expression Trees no momento.


3
Eu tenho uma classe reflexão utilitário que faz o mesmo com FieldInfo, PropertyInfo, etc ...
Olmo

Sim, isso é ótimo. Consegui usar métodos como esse para escrever códigos como EditValue(someEmployee, e => e.FirstName);na minha lógica de negócios e gerar automaticamente toda a lógica de encanamento para um ViewModel e View para editar essa propriedade (portanto, um rótulo com o texto "Primeiro nome" e um TextBox com uma ligação que chama o setter da propriedade FirstName quando o usuário edita o nome e atualiza a View usando o getter). Essa parece ser a base para a maioria dos novos DSLs internos em C #.
Scott Whitlock

4
Eu acho que esses não são tão menos conhecidos quanto menos compreendidos.
Justin Morgan

Por que você precisa registrar um método? Eu nunca usei isso antes - onde e quando isso seria usado?
precisa saber é o seguinte

209

" rendimento " viria à minha mente. Alguns dos atributos como [DefaultValue ()] também estão entre os meus favoritos.

A palavra-chave " var " é um pouco mais conhecida, mas você também pode usá-la em aplicativos .NET 2.0 (desde que você use o compilador .NET 3.5 e defina-o para gerar o código 2.0) não parece ser muito conhecido. bem.

Edit: kokos, obrigado por apontar o ?? operador, isso é realmente muito útil. Como é um pouco difícil pesquisar no Google (como ?? é apenas ignorado), aqui está a página de documentação do MSDN para esse operador: ?? Operador (Referência de C #)


14
A documentação do valor padrão diz que não está realmente definindo o valor da propriedade. É apenas um auxiliar para visualizadores e geradores de código.
Boris Callens

2
Quanto ao DefaultValue: Enquanto isso, algumas bibliotecas o usam. O ASP.net MVC usa DefaultValue nos parâmetros de uma ação do controlador (o que é muito útil para tipos não anuláveis). Estritamente falando, é claro, este é um gerador de código, pois o valor não é definido pelo compilador, mas pelo código do MVC.
Michael Stum

6
O nome para o ?? operator é o operador "Null Coalescing"
Armstrongest

O yield é o meu favorito, embora o operador de coalescência esteja lá em cima. Não vejo nada sobre o CAS ou assinatura de assemblagem, nomes fortes, o GAC ... Suponho que apenas o CAS seja C # ... mas muitos desenvolvedores não têm idéia sobre segurança.
BrainSlugs83

198

Costumo descobrir que a maioria dos desenvolvedores de C # não conhece os tipos 'anuláveis'. Basicamente, primitivas que podem ter um valor nulo.

double? num1 = null; 
double num2 = num1 ?? -100;

Defina um duplo anulável, num1 , como nulo, depois defina um duplo regular, num2 , para num1 ou -100 se num1 for nulo.

http://msdn.microsoft.com/en-us/library/1t3y8s4s(VS.80).aspx

mais uma coisa sobre o tipo Nullable:

DateTime? tmp = new DateTime();
tmp = null;
return tmp.ToString();

é retornar String.Empty. Verifique este link para mais detalhes


1
DateTime não pode ser definido como nulo.
Jason Jackson

2
Então, "int" é apenas o açúcar sintático em C # para System.Int32? Na verdade, há suporte ao compilador criado em torno dos tipos Nullable, permitindo configurá-los como nulos, por exemplo (o que não pode ser feito apenas com estruturas genéricas) e encaixotando-os como seu tipo subjacente.
P Daddy

4
@ P Daddy - sim, int é açúcar sintático para System.Int32. Eles são completamente intercambiáveis, assim como int? === Int32? === Nullable <Int32> === Nullable <int>
cjk

6
@ck: Sim, int é um apelido para System.Int32, como T? é um alias para Nullable <T>, mas não é apenas açúcar sintático. É uma parte definida da linguagem. Os aliases não apenas facilitam a leitura do código, mas também se ajustam melhor ao nosso modelo. Expressando Nullable <Double> como duplo? sublinha a perspectiva de que o valor assim contido é (ou pode ser) um duplo, não apenas uma estrutura genérica instanciada no tipo Double. (continuação)
P Daddy

3
... De qualquer forma, o argumento não era sobre aliases (isso era apenas uma analogia ruim, suponho), mas esses tipos anuláveis ​​- usando qualquer sintaxe que você preferir - são realmente um recurso de linguagem, não apenas um produto de genéricos. Você não pode reproduzir toda a funcionalidade de nulos (comparação / designação de nulo, encaminhamento de operador, boxe de tipo subjacente ou nulo, compatibilidade com coalescência e asoperadores nulos ) apenas com genéricos. Nullable <T> por si só é rudimentar e longe de ser estelar, mas o conceito de tipos nulos como parte da linguagem é sensacional.
P Daddy

193

Aqui estão alguns recursos interessantes de C # ocultos, na forma de palavras-chave em C # não documentadas:

__makeref

__reftype

__refvalue

__arglist

Essas são palavras-chave em C # não documentadas (até o Visual Studio as reconhece!) Que foram adicionadas a um boxe / unboxing mais eficiente antes dos genéricos. Eles trabalham em coordenação com a estrutura System.TypedReference.

Há também __arglist, que é usado para listas de parâmetros de comprimento variável.

Uma coisa que as pessoas não sabem muito é o System.WeakReference - uma classe muito útil que monitora um objeto, mas ainda permite que o coletor de lixo o colete.

O recurso "oculto" mais útil seria a palavra-chave return return. Não está realmente escondido, mas muitas pessoas não sabem disso. O LINQ é construído sobre isso; Ele permite consultas executadas com atraso, gerando uma máquina de estado sob o capô. Raymond Chen postou recentemente sobre os detalhes internos e arenosos .



@HuBeZa com o advento dos genéricos, não existem muitas (boas?) Boas razões para usar __refType, __makeref e __refvalue. Estes foram usados principalmente para evitar boxe antes de genéricos no .NET 2.
Judah Gabriel Himango

Matt, com a introdução de genéricos no .NET 2, há poucas razões para usar essas palavras-chave, pois seu objetivo era evitar o boxe ao lidar com tipos de valor. Veja o link por HuBeZa, e também ver codeproject.com/Articles/38695/UnCommon-C-keywords-A-Look#ud
Judah Gabriel Himango

185

Uniões (o tipo de memória compartilhada C ++) em C # puro e seguro

Sem recorrer ao modo não seguro e aos ponteiros, você pode fazer com que os membros da classe compartilhem espaço de memória em uma classe / estrutura. Dada a seguinte classe:

[StructLayout(LayoutKind.Explicit)]
public class A
{
    [FieldOffset(0)]
    public byte One;

    [FieldOffset(1)]
    public byte Two;

    [FieldOffset(2)]
    public byte Three;

    [FieldOffset(3)]
    public byte Four;

    [FieldOffset(0)]
    public int Int32;
}

Você pode modificar os valores dos campos de bytes manipulando o campo Int32 e vice-versa. Por exemplo, este programa:

    static void Main(string[] args)
    {
        A a = new A { Int32 = int.MaxValue };

        Console.WriteLine(a.Int32);
        Console.WriteLine("{0:X} {1:X} {2:X} {3:X}", a.One, a.Two, a.Three, a.Four);

        a.Four = 0;
        a.Three = 0;
        Console.WriteLine(a.Int32);
    }

Emite isso:

2147483647
FF FF FF 7F
65535

basta adicionar using System.Runtime.InteropServices;


7
@ George, faz maravilhas quando você está se comunicando com aplicativos herdados por soquetes usando declarações c union.
scottm

2
Também é significativo dizer int e flutuar no deslocamento 0. É o que você precisa para manipular números de ponto flutuante como máscaras de bits, o que às vezes você deseja. Especialmente se você quiser aprender coisas novas sobre números de ponto flutuante.
John Leidegren

2
A coisa chata sobre isso é que, se você for usar esta é uma estrutura, o compilador o forçará a definir TODAS as variáveis ​​na função init. Portanto, se você tiver: public A (int int32) {Int32 = int32; } ele exibirá "O campo 'Um' deve ser totalmente atribuído antes que o controle seja retornado ao chamador"; portanto, você deve definir Um = Dois = Três = Quatro = 0 = 0; também.
Manixrock 01/10/09

2
Isso tem seus usos, principalmente com dados binários. Eu uso uma estrutura "Pixel" com um int32 @ 0 e quatro bytes para os quatro componentes @ 0, 1, 2 e 3. Ótimo para manipular dados de imagem com rapidez e facilidade.
snarf 16/10/09

57
Aviso: Esta abordagem não leva em consideração o endianness. Isso significa que seu código C # não será executado da mesma maneira em todas as máquinas. Em CPUs little-endian (que armazenam o byte menos significativo primeiro), o comportamento mostrado será usado. Mas em CPUs big-endian, os bytes serão revertidos do que você esperava. Cuidado com o modo como você usa isso no código de produção - seu código pode não ser portátil para determinados dispositivos móveis e outros hardwares e pode quebrar de maneiras não óbvias (por exemplo, dois arquivos ostensivamente no mesmo formato, mas na verdade com a ordem dos bytes invertida).
Ray Burns,

176

Usando @ para nomes de variáveis ​​que são palavras-chave.

var @object = new object();
var @string = "";
var @if = IpsoFacto(); 

38
Por que você deseja usar uma palavra-chave como nome de variável? Parece-me que isso tornaria o código menos legível e ofuscado.
Jon Jon

41
Bem, a razão que ele está lá é que CLI exige para interoperabilidade com outras linguagens que podem usar C # palavras-chave como nomes de membros
Mark Cidade

69
Se você sempre quis usar o asp.net MVC HTML ajudantes e definir uma classe HTML você vai ficar feliz em saber que você pode usar @class por isso não vai ser reconhecida como a palavra-chave class
Boris Callens

31
Ótimo para métodos de extensão. public static void DoSomething (esse Bar @this, string foo) {...}
Jonathan C Dickinson

45
@zihotki: Errado. var a = 5; Console.WriteLine (@a); Impressões 5
SLaks

168

Se você quiser sair do seu programa sem chamar nenhum bloco ou finalizador, use o FailFast :

Environment.FailFast()

12
Observe que esse método também cria um despejo de memória e grava uma mensagem no log de erros do Windows.
21909 RickNZ

1
Deve-se notar há finalizadores ou aplicativos eventos descarregamento de domínio será chamado quando este método é usado ...
AwkwardCoder

1
+1 para a dica, mas esse não é o C #, é o BCL do .NET.
Abel

System.Diagnostics.Process.GetCurrentProcess (). Kill () é mais rápido
Tolgahan Albayrak

153

Retornando tipos anônimos de um método e acessando membros sem reflexão.

// Useful? probably not.
private void foo()
{
    var user = AnonCast(GetUserTuple(), new { Name = default(string), Badges = default(int) });
    Console.WriteLine("Name: {0} Badges: {1}", user.Name, user.Badges);
}

object GetUserTuple()
{
    return new { Name = "dp", Badges = 5 };
}    

// Using the magic of Type Inference...
static T AnonCast<T>(object obj, T t)
{
   return (T) obj;
}

42
Isso realmente não te dá nada. É realmente perigoso. E se GetUserTuple for modificado para retornar vários tipos? O elenco falhará no tempo de execução. Uma das grandes coisas do C # /. Net é a verificação do tempo de compilação. Seria muito melhor criar apenas um novo tipo.
Jason Jackson

9
@ Jason, eu disse que provavelmente não é útil, mas é surpreendente (e eu pensei que estava escondido).
Denis phillips

31
Embora seja legal, isso parece uma escolha de design bastante ruim. Você basicamente definiu o tipo anônimo em dois lugares. Nesse ponto, basta declarar uma estrutura real e usá-la diretamente.
Paul Alexander

6
@ George: essa convenção seria chamada de ... struct?
R. Martinho Fernandes

2
esse truque é chamado de 'conversão por amostra' e não funcionará se o método que retorna o tipo anônimo estiver localizado em outro assembly.
desco

146

Aqui está um útil para expressões regulares e caminhos de arquivo:

"c:\\program files\\oldway"
@"c:\program file\newway"

O @ diz ao compilador para ignorar qualquer caractere de escape em uma string.


27
Além disso, uma constante @ aceita novas linhas dentro. Perfeito ao atribuir um script de múltiplas linhas a uma string.
Tor Haugen

11
Não se esqueça também de escapar de aspas, apenas dobrá-las, em outras palavras. [code] var candy = @ "Eu gosto de" "vermelho" "bastões de doces."; [/ code]
Dave

5
Costumo construir caminhos com Path.Combine. Definitivamente eu uso o @ para regex!
21411 Dan McClain

6
@New também é uma variável em vez de uma palavra-chave: @this, @int, @return, @interface ... assim por diante :)
iAbstract

Este não chega nem perto: mas quais são os recursos ou truques mais ocultos do C # que até os fãs, viciados e especialistas em C # mal conhecem?
publicgk

141

Mixins. Basicamente, se você deseja adicionar um recurso a várias classes, mas não pode usar uma classe base para todas elas, peça a cada classe que implemente uma interface (sem membros). Em seguida, escreva um método de extensão para a interface , ou seja,

public static DeepCopy(this IPrototype p) { ... }

Claro, alguma clareza é sacrificada. Mas funciona!


4
Sim, acho que esse é o verdadeiro poder dos métodos de extensão. Eles basicamente permitem implementações de métodos de interface.
John Bubriski

Isso também é útil se você estiver usando o NHibernate (ou Castle ActiveRecord) e precisar usar interfaces para suas coleções. Dessa forma, você pode dar comportamento às interfaces de coleção.
precisa

É basicamente assim que todos os métodos LINQ são implementados, para constar.
WCWedin

Aqui está um link que fala sobre o que me referi acima, usando métodos de extensão com interfaces de coleta em NHibernate ou Castle ActiveRecord: devlicio.us/blogs/billy_mccafferty/archive/2008/09/03/...
Ryan Lundy

7
Se eles permitissem propriedades de extensão !!!! Eu odiava ter que escrever um método de extensão que implorou para ser uma propriedade só de leitura ....
John Gibb

130

Não sei por que alguém iria querer usar o <bool> Nullable. :-)

Verdadeiro, falso, FileNotFound ?


87
se esperar que um usuário para responder a sim não pergunta então nulo seria apropriado se a pergunta não foi respondida
Omar Kooheji

22
Tipos anuláveis ​​são úteis para interação com um banco de dados em que as colunas da tabela geralmente são anuláveis.
Tuinstoel

11
Sim, não, Maybee?
2111 Dan Blair

21
Armazenar valores de um ThreeState CheckBox
Shimmy Weitzhandler

8
Como no SQL: Sim / não / desconhecido.
erikkallen

116

Este não é "escondido" tanto quanto é nomeado incorretamente.

Muita atenção é dada aos algoritmos "mapa", "redução" e "filtro". O que a maioria das pessoas não percebe é que o .NET 3.5 adicionou todos esses três algoritmos, mas deu a eles nomes muito SQL-ish, com base no fato de que eles fazem parte do LINQ.

"map" => Selecionar
Transforma dados de um formulário para outro

"reduzir" => Agregar
Agrega valores em um único resultado

"filter" => Onde
Filtra dados com base em um critério

A capacidade de usar o LINQ para realizar trabalhos em linha em coleções que costumavam fazer iterações e condicionais pode ser incrivelmente valiosa. Vale a pena aprender como todos os métodos de extensão LINQ podem ajudar a tornar seu código muito mais compacto e sustentável.


1
Selecionar também atua como a função "retornar" em mônadas. Veja stackoverflow.com/questions/9033/hidden-features-of-c#405088
Mark Cidade

1
O uso de "select" é necessário apenas se você usar a sintaxe SQLish. Se você usar a sintaxe do método de extensão - someCollection.Where (item => item.Price> 5.99M) - o uso de instruções select não será necessário.
Brad Brad Wilson

7
@ Brad, que (onde) é uma operação de filtro. Tente fazer uma operação de mapa sem selecionar ...
Eloff 10/10

2
LINQ é a grande coisa que aconteceu com C # na minha opinião: stackoverflow.com/questions/2398818/...
Leniel Maccaferri

1
A menor assinatura do Agregado é a função "reduzir", a assinatura do meio do Agregado é a função "dobrar" muito mais poderosa!
Brett Widmeier

115
Environment.NewLine

para novas linhas independentes do sistema.


10
A coisa chata sobre este é que ele não está incluído na estrutura compacta.
Stormenet 08/12/08

14
Vale ressaltar que isso é específico da plataforma host do aplicativo - portanto, se você estiver criando dados destinados a outro sistema, use \ n ou \ r \ n adequadamente.
malha

Isso faz parte do BCL do .NET, não um recurso do C # por si só.
Abel

111

Se você estiver tentando usar colchetes dentro de uma expressão String.Format ...

int foo = 3;
string bar = "blind mice";
String.Format("{{I am in brackets!}} {0} {1}", foo, bar);
//Outputs "{I am in brackets!} 3 blind mice"

19
@ Kyralessa: Na verdade, sim, eles são suspensórios, mas "colchetes" é um nome alternativo para eles. [e ]são colchetes <e >são colchetes angulares. Consulte en.wikipedia.org/wiki/Bracket .
icktoofay

4
Você está certo. Mas quando eu comentei, não dizia colchetes.
Ryan Lundy

2
Muito bom de salientar. Lembre-se do meu primeiro String.Format: String.Format ("{0} estou entre colchetes {1} {2} {3}", "{", "}", 3, "ratos cegos"); Uma vez eu descobri que escapar deles é feito usando {{e}} Eu estava tão feliz :)
Gertjan

Muahahahaa ... Programando já 3 anos no .Net e eu não conhecia esse. : D
Arnis Lapsa

colchetes "cacheados" agindo de maneira semelhante às seqüências de escape?
Pratik

104
  1. ?? - operador coalescente
  2. using ( declaração / diretiva ) - excelente palavra-chave que pode ser usada para mais do que chamar Dispose
  3. somente leitura - deve ser usado mais
  4. netmodules - pena que não há suporte no Visual Studio

6
using também pode ser usado para alias um namespace longo para uma string mais conveniente, ou seja: using ZipEncode = MyCompany.UtilityCode.Compression.Zip.Encoding; Há mais aqui: msdn.microsoft.com/en-us/library/sf0df423.aspx
Dave R.

2
Realmente não é a mesma coisa. Ao chamar Dispose, você pode usar a instrução using, ao usar o alias de tipos usando uma diretiva using.
Øyvind Skaar

2
Caso você queira um nome para o número 1 (como fez com o operador ternário), ?? é chamado de operador coalescente nulo.
314/09 J. Steen

4
@LucasAardvark: Como J Steen mencionou, é chamado de operador coalescente nulo. Procure por isso!
21410

1
Procurar por ?? operador no google try: google.com/search?q=c%23+%3F%3F+operator
backslash17

103

@ Ed, eu sou um pouco reticente em postar isso, pois é pouco mais do que nitpicking. No entanto, gostaria de salientar que no seu exemplo de código:

MyClass c;
  if (obj is MyClass)
    c = obj as MyClass

Se você vai usar 'is', por que segui-lo com um elenco seguro usando 'as'? Se você constatou que obj é, de fato, MyClass, um elenco padrão:

c = (MyClass)obj

... nunca vai falhar.

Da mesma forma, você poderia apenas dizer:

MyClass c = obj as MyClass;
if(c != null)
{
   ...
}

Não sei o suficiente sobre as entranhas do .NET para ter certeza, mas meus instintos me dizem que isso reduziria no máximo dois tipos de operações de conversão para um máximo de um. É pouco provável que quebre o banco de processamento de qualquer maneira; pessoalmente, acho que a última forma parece mais limpa também.


16
Se a conversão for do tipo exato (conversão para "A" quando o objeto for "A", não derivado dela), a conversão direta será ~ 3x MAIS RÁPIDA que "como". Ao converter um tipo derivado (convertido para "A" quando o objeto é "B", que deriva de "A"), a conversão direta é ~ 0,1x mais lenta que "como". "é", então "como" é bobo.
P papai

2
Não, mas você pode escrever "if ((c = obj como MyClass)! = Null)".
Dave Van den Eynde 25/03/2009

10
ise asnão fará transmissões de usuários. Portanto, o código acima está perguntando ao isoperador se obj é derivado de MyClass (ou tem uma conversão definida implícita no sistema). Além disso, isfalha null. Ambos os casos extremos podem ser importantes para o seu código. Por exemplo, você pode escrever: if( obj == null || obj is MyClass ) c = (MyClass)obj; Mas isso é estritamente diferente de: try { c = (MyClass)obj; } catch { }como o primeiro não realizará nenhuma conversão definida pelo usuário, mas o segundo o fará. Sem a nullverificação, o primeiro também não definirá cquando objestá null.
9119 Adam Luter

2
Em IL, um elenco vai para uma CASTCLASS, mas um as / is vai para uma instrução ISINST.
John Gibb

5
Fiz um teste para isso, lançando IEnumerable<int>para List<int>e lançando object( new object()) para IEnumerable<int>, para garantir que não haja erros: elenco direto: 5.43ns, é-> como elenco: 6.75ns, como elenco: 5.69ns. Em seguida, testando lançamentos inválidos: elenco direto: 3125000ns, como elenco: 5.41ns. Conclusão: pare de se preocupar com o fator de 1% e certifique-se de que você use / como quando o elenco for inválido, pois as exceções (também se tratadas) são MUITO lentas em comparação com a transmissão, estamos falando de um fator 578000 mais lento. Lembre-se essa última parte, o resto não importa (.Net FW 4.0, compilação de lançamento)
Aidiakapi

98

Talvez não seja uma técnica avançada, mas eu vejo o tempo todo que me deixa louco:

if (x == 1)
{
   x = 2;
}
else
{
   x = 3;
}

pode ser condensado para:

x = (x==1) ? 2 : 3;

10
O operador ternário foi banido no meu grupo. Algumas pessoas simplesmente não gostam, embora eu nunca tenha entendido o porquê.
Justin R.

13
Eu acho que porque não são as mesmas coisas, ser um operador, não uma afirmação. Eu prefiro a primeira abordagem. É mais consistente e facilmente expansível. Os operadores não podem conter declarações, assim que o minuto em que você tem que expandir o corpo, você vai ter que converter esse operador ternário para uma instrução if
kervin

16
pode ser condensado para x ++; Ok é ^^ inútil
François

5
@ Guillaume: Para contabilizar todos os valores de x: x = 2 + System.Math.Min (1, System.Math.Abs ​​(x-1));
mbeckish

38
Na verdade, é chamado de "operador condicional" - é um operador ternário porque leva três argumentos. en.wikipedia.org/wiki/Conditional_operator
Blorgbeard está fora
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.