Recursos ocultos do c #?

Isso veio à minha mente depois que eu aprendi o seguinte desta pergunta :

where T : struct 

Nós, desenvolvedores C #, todos sabemos o básico do C #. Quero dizer declarações, condicionais, loops, operadores, etc.

Alguns de nós até dominamos as coisas como Generics , tipos anônimos , lambdas , LINQ , …

Mas quais são os resources mais ocultos ou truques do C # que mesmo os fãs de C #, viciados, especialistas mal sabem?

Aqui estão os resources revelados até agora:

Palavras-chave

  • yield por Michael Stum
  • var de Michael Stum
  • declaração using() por kokos
  • readonly por kokos
  • as por Mike Stone
  • as / is de Ed Swangren
  • as / is (improved) por Rocketpants
  • default por deathofrats
  • global:: por pzycoman
  • using() blocos por AlexCuse
  • volatile por Jakub Šturc
  • extern alias por Jakub Šturc

Atributos

  • DefaultValueAttribute de Michael Stum
  • ObsoleteAttribute by DannySmurf
  • DebuggerDisplayAttribute by Stu
  • DebuggerBrowsable e DebuggerStepThrough por bdukes
  • ThreadStaticAttribute por marxidad
  • FlagsAttribute de Martin Clarke
  • ConditionalAttribute por AndrewBurns

Sintaxe

  • ?? (coalesce nulls) operator por kokos
  • Flagra de número por Nick Berardi
  • where T:new por Lars Mæhlum
  • Genéricos implícitos por Keith
  • Lambda de um parâmetro por Keith
  • Auto propriedades de Keith
  • Aliases do namespace por Keith
  • Literais de string verbatim com @ por Patrick
  • valores de enum por lfoust
  • @variablenames por marxidad
  • operadores de event por marxidad
  • Formatar colchetes por Portman
  • Modificadores de acessibilidade de accessr de propriedade por xanadont
  • Operador condicional (ternário) ( ?: 🙂 Por JasonS
  • operadores checked e unchecked por Binoj Antony
  • operadores implicit and explicit por Flory

Caracteristicas do idioma

  • Tipos anuláveis ​​por Brad Barker
  • Tipos anônimos por Keith
  • __makeref __reftype __refvalue por Judah Himango
  • Inicializadores de object por lomaxx
  • Formato de cordas por David em Dakota
  • Métodos de extensão por marxidad
  • methods partial por Jon Erickson
  • Diretivas de pré-processador de John Asbeck
  • Diretiva de pré-processador DEBUG por Robert Durgin
  • Sobrecarga de operador por SefBkn
  • Digite inferrence por chakrit
  • Operadores booleanos levados para o próximo nível por Rob Gough
  • Variável de valor de passagem como interface sem boxe por Roman Boiko
  • Programaticamente determinar tipo de variável declarada por Roman Boiko
  • Construtores estáticos por Chris
  • Mapeamento de ORM mais fácil de enxergar / condensado usando LINQ by roosteronacid
  • __arglist por Zac Bowling

Recursos do Visual Studio

  • Selecione o bloco de texto no editor por Himadri
  • Trechos por DannySmurf

Estrutura

  • TransactionScope por KiwiBastard
  • DependantTransaction por KiwiBastard
  • Nullable por IainMH
  • Mutex por Diago
  • System.IO.Path por ageektrapped
  • WeakReference por Juan Manuel

Métodos e Propriedades

  • Método String.IsNullOrEmpty() por KiwiBastard
  • List.ForEach() método por KiwiBastard
  • BeginInvoke() , EndInvoke() methods por Will Dean
  • Propriedades Nullable.HasValue e Nullable.Value por Rismo
  • Método GetValueOrDefault por John Sheehan

dicas e truques

  • Bom método para manipuladores de events por Andreas HR Nilsson
  • Comparações de maiúsculas por John
  • Acesse tipos anônimos sem reflection por dp
  • Uma maneira rápida de instanciar propriedades de coleção por Will
  • Funções inline anônimas como JavaScript por roosteronacid

De outros

  • netmodules por kokos
  • LINQBridge por Duncan Smart
  • Extensões paralelas por Joel Coehoorn

    Este não é C # per se, mas eu não vi ninguém que realmente usa System.IO.Path.Combine() na medida em que deveriam. Na verdade, toda a class 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; 

    lambdas e tipo inferrence são subestimados. Os Lambdas podem ter várias instruções e duplicar automaticamente como um object delegado compatível (apenas certifique-se de que a correspondência de assinatura), como em:

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

    Note que eu não tenho um new CancellationEventHandler nem tenho que especificar os tipos de sender e , eles são inferíveis a partir do evento. É por isso que isso é menos complicado para escrever todo o delegate (blah blah) que também requer que você especifique os tipos de parâmetros.

    Lambdas não precisam retornar nada e inferência de tipos é extremamente poderosa em contexto como este.

    E BTW, você sempre pode retornar Lambdas que fazem Lambdas no sentido de functional programming. Por exemplo, aqui está um lambda que faz um lambda que manipula um evento Button.Click:

     Func 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 tido a aula de functional programming 🙂

    Além dos pointers em C, eu acho que é a outra coisa fundamental que você deve aprender 🙂

    De Rick Strahl :

    Você pode encadear o ?? operador para que você possa fazer um monte de comparações nulas.

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

    Genéricos com alias:

     using ASimpleName = Dictionary>>; 

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

    Use-o quando você usaria o mesmo genérico grande complexo longo em muitos lugares.

    Do CLR via C # :

    Ao normalizar cadeias de caracteres, é altamente recomendável que você use ToUpperInvariant em vez de ToLowerInvariant porque a Microsoft otimizou o código para executar comparações de maiúsculas .

    Lembro-me de uma vez que meu colega de trabalho sempre mudava as strings para maiúsculas antes de comparar. Sempre me perguntei por que ele faz isso porque acho mais “natural” converter em minúscula primeiro. Depois de ler o livro agora eu sei porque.

    Meu truque favorito é usar o operador de união neutra e parênteses para instanciar automaticamente as collections para mim.

     private IList _foo; public IList ListOfFoo { get { return _foo ?? (_foo = new List()); } } 

    Evite a verificação de manipuladores de events nulos

    Adicionando um delegado vazio para events na declaração, suprimindo a necessidade de sempre verificar o evento para null antes de chamar é incrível. 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 este post de Eric Lippert sobre este tópico (e possíveis desvantagens).

    Tudo mais, mais

    1) genéricos implícitos (por que apenas em methods e não em classs?)

     void GenericMethod( T input ) { ... } //Infer type, so GenericMethod(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 { { "red", "#ff0000" }, { "green", "#00ff00" }, { "blue", "#0000ff" } }; int[] arrayOfInt = { 1, 2, 3, 4, 5 }; 

    Outro:

    4) Propriedades automáticas podem ter diferentes escopos:

     public int MyId { get; private set; } 

    Obrigado @pzycoman por me lembrar:

    5) Pseudônimos de namespace (não é provável 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(); 

    Eu não sabia 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 MyClass, em vez de lançar uma exceção de cast de class.

    Duas coisas que eu gosto são propriedades automáticas para que você possa reduzir seu código ainda mais:

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

    torna-se

     public string Name { get; set;} 

    Também inicializadores de object:

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

    torna-se

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

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

     T t = default(T); 

    resulta em um ‘null’ se T for um tipo de referência e 0 se for um int, falso se for um booleano, etc.

    Atributos em geral, mas acima de tudo DebuggerDisplay . Te poupa anos.

    O @ diz ao compilador para ignorar quaisquer caracteres de escape em uma string.

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

    Se você tem

     string s = @"cat dog fish" 

    Na verdade, ele será impresso como (observe que ele inclui até o espaço em branco usado para recuo):

     cat dog fish 

    Eu acho que um dos resources mais subestimados e menos conhecidos do C # (.NET 3.5) são Árvores de Expressão , especialmente quando combinadas com Generics e Lambdas. Esta é uma abordagem para a criação de APIs que as bibliotecas mais novas, como NInject e Moq, estão usando.

    Por exemplo, digamos que eu queira registrar um método com uma API e essa API precisa obter o nome do método

    Dada esta class:

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

    Antes, era muito comum ver os desenvolvedores fazendo isso com strings e tipos (ou algo muito baseado em strings):

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

    Bem, isso é uma droga por causa da falta de digitação forte. E se eu renomear “SomeMethod”? Agora, no 3.5, no entanto, posso fazer isso de uma forma fortemente tipificada:

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

    Em que a class RegisterMethod usa Expression> assim:

     void RegisterMethod(Expression> action) where T : class { var expression = (action.Body as MethodCallExpression); if (expression != null) { // TODO: Register method Console.WriteLine(expression.Method.Name); } } 

    Este é um grande motivo pelo qual estou apaixonado por Lambdas e Expression Trees agora.

    ” rendimento ” viria a 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 (contanto que você use o compilador .NET 3.5 e configurá-la para gerar o código 2.0) não parece ser muito conhecida bem.

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

    Eu tenho a tendência de descobrir que a maioria dos desenvolvedores de C # não sabe sobre os tipos ‘anuláveis’. Basicamente, primitivos que podem ter um valor nulo.

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

    Defina um double anulável, num1 , para null e defina um double regular, num2 , para num1 ou -100, se num1 for null.

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

    é return String.Empty. Confira este link para mais detalhes

    Aqui estão alguns resources interessantes do C #, sob a forma de palavras-chave não documentadas em C #:

     __makeref __reftype __refvalue __arglist 

    Estas são palavras-chave C # não documentadas (até mesmo o Visual Studio as reconhece!) Que foram adicionadas para um boxe / desempacotamento 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 tamanho variável.

    Uma coisa sobre a qual as pessoas não sabem muito é System.WeakReference – uma class muito útil que controla um object, mas ainda permite ao coletor de lixo coletá-lo.

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

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

    Sem recorrer a modos e pointers inseguros, você pode fazer com que os alunos compartilhem espaço de memory em uma class / struct. Dada a seguinte class:

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

    Produz isto:

     2147483647 FF FF FF 7F 65535 

    Basta adicionar usando System.Runtime.InteropServices;

    Usando @ para nomes de variables ​​que são palavras-chave.

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

    Se você quiser sair do seu programa sem chamar finalmente algum bloco ou finalizador use FailFast :

     Environment.FailFast() 

    Retornando tipos anônimos de um método e acessando membros sem reflection.

     // 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(object obj, T t) { return (T) obj; } 

    Here’s a useful one for regular expressions and file paths:

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

    The @ tells the compiler to ignore any escape characters in a string.

    Mixins. Basically, if you want to add a feature to several classs, but cannot use one base class for all of them, get each class to implement an interface (with no members). Then, write an extension method for the interface , ie

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

    Of course, some clarity is sacrificed. But it works!

    Not sure why anyone would ever want to use Nullable though. 🙂

    True, False, FileNotFound ?

    This one is not “hidden” so much as it is misnamed.

    A lot of attention is paid to the algorithms “map”, “reduce”, and “filter”. What most people don’t realize is that .NET 3.5 added all three of these algorithms, but it gave them very SQL-ish names, based on the fact that they’re part of LINQ.

    “map” => Select
    Transforms data from one form into another

    “reduce” => Aggregate
    Aggregates values into a single result

    “filter” => Where
    Filters data based on a criteria

    The ability to use LINQ to do inline work on collections that used to take iteration and conditionals can be incredibly valuable. It’s worth learning how all the LINQ extension methods can help make your code much more compact and maintainable.

     Environment.NewLine 

    for system independent newlines.

    If you’re trying to use curly brackets inside a String.Format expression…

     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" 
    1. ?? – coalescing operator
    2. using ( statement / directive ) – great keyword that can be used for more than just calling Dispose
    3. readonly – should be used more
    4. netmodules – too bad there’s no support in Visual Studio

    @Ed, I’m a bit reticent about posting this as it’s little more than nitpicking. However, I would point out that in your code sample:

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

    If you’re going to use ‘is’, why follow it up with a safe cast using ‘as’? If you’ve ascertained that obj is indeed MyClass, a bog-standard cast:

     c = (MyClass)obj 

    …is never going to fail.

    Similarly, you could just say:

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

    I don’t know enough about .NET’s innards to be sure, but my instincts tell me that this would cut a maximum of two type casts operations down to a maximum of one. It’s hardly likely to break the processing bank either way; personally, I think the latter form looks cleaner too.

    Maybe not an advanced technique, but one I see all the time that drives me crazy:

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

    can be condensed to:

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