Características ocultas de C #?

Esto vino a mi mente después de que aprendí lo siguiente de esta pregunta :

where T : struct 

Nosotros, los desarrolladores de C #, todos conocemos los conceptos básicos de C #. Me refiero a declaraciones, condicionales, bucles, operadores, etc.

Algunos de nosotros incluso dominamos cosas como generics , tipos anónimos , lambdas , LINQ , …

Pero, ¿cuáles son las características o trucos más ocultos de C # que incluso los fanáticos de C #, los adictos, los expertos apenas conocen?

Aquí están las características reveladas hasta ahora:

Palabras clave

  • yield de Michael Stum
  • var por Michael Stum
  • using() statement por kokos
  • readonly por kokos
  • as por Mike Stone
  • as / is by Ed Swangren
  • as / is (mejorado) por Rocketpants
  • default por deathofrats
  • global:: por pzycoman
  • using() bloques de AlexCuse
  • volatile por Jakub Šturc
  • extern alias por Jakub Šturc

Atributos

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

Sintaxis

  • ?? (coalesce nulls) operador por kokos
  • Número de banderas de Nick Berardi
  • where T:new por Lars Mæhlum
  • Genéricos implícitos por Keith
  • Un solo parámetro lambdas por Keith
  • Propiedades automáticas de Keith
  • Namespace alias de Keith
  • Literales literales literales con @ de Patrick
  • valores enum por lfoust
  • @variablenames por marxidad
  • operadores de event por marxidad
  • Formato de corchetes por Portman
  • Modificadores de accesibilidad de acceso de propiedad por xanadont
  • Operador condicional (ternario) ( ?: 🙂 Por JasonS
  • operadores marcados y unchecked marcados por Binoj Antony
  • operadores implicit and explicit de Flory

Características del lenguaje

  • Tipos anulables por Brad Barker
  • Tipos anónimos por Keith
  • __makeref __reftype __refvalue por Judah Himango
  • Iniciales de objetos por lomaxx
  • Cadenas de formato de David en Dakota
  • Extension Methods por marxidad
  • métodos partial por Jon Erickson
  • Directivas de preprocesador de John Asbeck
  • Directiva de preprocesamiento DEBUG por Robert Durgin
  • Sobrecarga del operador por SefBkn
  • Escriba inferrence por chakrit
  • Operadores booleanos llevados al siguiente nivel por Rob Gough
  • Pasar variable de tipo valor como interfaz sin boxeo por Roman Boiko
  • Determinado programáticamente el tipo de variable declarada por Roman Boiko
  • Static Constructors por Chris
  • Cartografía ORM más fácil en los ojos / condensada usando LINQ por roosteronacid
  • __arglist por Zac Bowling

Características de Visual Studio

  • Seleccionar el bloque de texto en el editor de Himadri
  • Snippets por DannySmurf

Marco de referencia

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

Métodos y propiedades

  • String.IsNullOrEmpty() por KiwiBastard
  • List.ForEach() por KiwiBastard
  • BeginInvoke() , EndInvoke() por Will Dean
  • Nullable.HasValue y Nullable.Value properties by Rismo
  • Método GetValueOrDefault de John Sheehan

consejos y trucos

  • Un buen método para manipuladores de eventos por Andreas HR Nilsson
  • Comparaciones en mayúsculas por John
  • Acceda a tipos anónimos sin reflexión por dp
  • Una forma rápida de instanciar perezosamente las propiedades de la colección por Will
  • Funciones en línea anónimas similares a JavaScript de roosteronacid

Otro

  • netmodules por kokos
  • LINQBridge por Duncan Smart
  • Extensiones paralelas de Joel Coehoorn

    Esto no es C # per se, pero no he visto a nadie que realmente use System.IO.Path.Combine() en la medida en que deberían. De hecho, toda la clase Path es realmente útil, ¡pero nadie la usa!

    Estoy dispuesto a apostar que cada aplicación de producción tiene el siguiente código, aunque no debería:

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

    lambdas y la inferin tipo son infravaloradas. Lambdas puede tener varias declaraciones y se duplican como un objeto de delegado compatible automáticamente (solo asegúrese de que la coincidencia de la firma) como en:

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

    Tenga en cuenta que no tengo un new CancellationEventHandler ni tengo que especificar los tipos de sender y e , que son deducibles del evento. Por eso es menos complicado escribir todo el delegate (blah blah) que también requiere que especifique tipos de parámetros.

    Lambdas no necesita devolver nada y la inferencia de tipo es extremadamente poderosa en un contexto como este.

    Y por cierto, siempre puedes devolver Lambdas que hacen de Lambdas el sentido de la progtwigción funcional. Por ejemplo, aquí hay una lambda que crea una lambda que maneja un 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); 

    Tenga en cuenta el encadenamiento: (dx, dy) => (sender, e) =>

    Ahora es por eso que estoy feliz de haber tomado la clase de progtwigción funcional 🙂

    Aparte de los punteros en C, creo que es la otra cosa fundamental que debes aprender 🙂

    De Rick Strahl :

    Usted puede encadenar el ?? operador para que pueda hacer un montón de comparaciones nulas.

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

    Genéricos aliased:

     using ASimpleName = Dictionary>>; 

    Le permite usar ASimpleName , en lugar de Dictionary>> .

    Úselo cuando use la misma cosa genérica grande larga y compleja en muchos lugares.

    Desde CLR a través de C # :

    Al normalizar cadenas, se recomienda encarecidamente que utilice ToUpperInvariant en lugar de ToLowerInvariant porque Microsoft ha optimizado el código para realizar comparaciones en mayúsculas .

    Recuerdo una vez que mi compañero de trabajo siempre cambió las cuerdas a mayúsculas antes de compararlas. Siempre me he preguntado por qué lo hace porque creo que es más “natural” convertir primero a minúsculas. Después de leer el libro ahora sé por qué.

    Mi truco favorito es usar el operador nulo coalesce y paréntesis para crear automáticamente instancias de colecciones para mí.

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

    Evite buscar controladores de eventos nulos

    Agregar un delegado vacío a los eventos en la statement, suprimir la necesidad de comprobar siempre el evento para null antes de llamar es impresionante. Ejemplo:

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

    Dejate hacer esto

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

    En lugar de esto

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

    Consulte también este debate relacionado y esta publicación de blog de Eric Lippert sobre este tema (y posibles inconvenientes).

    Todo lo demás, más

    1) generics implícitos (¿por qué solo en los métodos y no en las clases?)

     void GenericMethod( T input ) { ... } //Infer type, so GenericMethod(23); //You don't need the <>. GenericMethod(23); //Is enough. 

    2) lambdas simples con un parámetro:

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

    3) tipos anónimos e inicializadores:

     //Duck-typed: works with any .Add method. var colours = new Dictionary { { "red", "#ff0000" }, { "green", "#00ff00" }, { "blue", "#0000ff" } }; int[] arrayOfInt = { 1, 2, 3, 4, 5 }; 

    Otro:

    4) Las propiedades automáticas pueden tener diferentes ámbitos:

     public int MyId { get; private set; } 

    Gracias @pzycoman por recordarme:

    5) Alias ​​del espacio de nombres (no es probable que necesites esta distinción particular):

     using web = System.Web.UI.WebControls; using win = System.Windows.Forms; web::Control aWebControl = new web::Control(); win::Control aFormControl = new win::Control(); 

    No sabía la palabra clave “como” desde hace bastante tiempo.

     MyClass myObject = (MyClass) obj; 

    vs

     MyClass myObject = obj as MyClass; 

    El segundo devolverá null si obj no es un MyClass, en lugar de arrojar una excepción de lanzamiento de clase.

    Dos cosas que me gustan son las propiedades automáticas, por lo que puedes colapsar aún más tu código:

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

    se convierte

     public string Name { get; set;} 

    También los inicializadores de objetos:

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

    se convierte

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

    La palabra clave ‘predeterminada’ en tipos generics:

     T t = default(T); 

    da como resultado un ‘nulo’ si T es un tipo de referencia, y 0 si es un int, falso si es un booleano, etcétera.

    Atributos en general, pero sobre todo DebuggerDisplay . Le ahorra años.

    El @ le dice al comstackdor que ignore cualquier carácter de escape en una cadena.

    Solo quería aclarar esto … no le dice que ignore los caracteres de escape, en realidad le dice al comstackdor que interprete la cadena como un literal.

    Si usted tiene

     string s = @"cat dog fish" 

    en realidad se imprimirá como (tenga en cuenta que incluso incluye el espacio en blanco utilizado para la sangría):

     cat dog fish 

    Creo que una de las características menos apreciadas y menos conocidas de C # (.NET 3.5) son Expression Trees , especialmente cuando se combinan con Generics y Lambdas. Este es un enfoque para la creación de API que usan las bibliotecas más nuevas como NInject y Moq.

    Por ejemplo, supongamos que quiero registrar un método con una API y esa API necesita obtener el nombre del método

    Dada esta clase:

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

    Antes, era muy común ver a los desarrolladores hacer esto con cadenas y tipos (o algo más basado principalmente en cadenas):

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

    Bueno, eso apesta por la falta de tipeado fuerte. ¿Qué sucede si cambio el nombre de “SomeMethod”? Ahora, en 3.5, sin embargo, puedo hacer esto de una manera fuertemente tipada:

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

    En el que la clase RegisterMethod usa Expression> esta manera:

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

    Esta es una gran razón por la que estoy enamorado de Lambdas y Expression Trees en este momento.

    ” rendimiento ” vendría a mi mente. Algunos de los atributos como [DefaultValue ()] también están entre mis favoritos.

    La palabra clave ” var ” es un poco más conocida, pero también se puede usar en aplicaciones .NET 2.0 (siempre y cuando use el comstackdor .NET 3.5 y lo configure en el código de salida 2.0). bien.

    Edit: kokos, gracias por señalar el ?? operador, eso de hecho es realmente útil. Dado que es un poco difícil encontrarlo en Google (como se ignora), esta es la página de documentación de MSDN para ese operador: Operador (referencia de C #)

    Tiendo a encontrar que la mayoría de los desarrolladores de C # no conocen los tipos de ‘anulables’. Básicamente, primitivas que pueden tener un valor nulo.

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

    Establezca un doble anulable, num1 , en nulo, luego establezca un doble regular, num2 , en num1 o -100 si num1 era nulo.

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

    una cosa más sobre el tipo Nullable:

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

    es return String.Empty. Mira este enlace para más detalles

    Aquí hay algunas características ocultas de C # interesantes, en forma de palabras clave de C # no documentadas:

     __makeref __reftype __refvalue __arglist 

    Estas son palabras clave de C # indocumentadas (¡incluso las reconoce Visual Studio!) Que se agregaron para un boxeo / unboxing más eficiente antes de los generics. Trabajan en coordinación con System.TypedReference struct.

    También hay __arglist, que se usa para listas de parámetros de longitud variable.

    Una cosa de la que la gente no sabe mucho es System.WeakReference , una clase muy útil que hace un seguimiento de un objeto pero que aún permite que el recolector de basura lo recolecte.

    La característica “oculta” más útil sería la palabra clave return yield. No está realmente oculto, pero mucha gente no lo sabe. LINQ está construido encima de esto; permite las consultas ejecutadas por demora al generar una máquina de estado bajo el capó. Raymond Chen publicó recientemente sobre los detalles internos y agresivos .

    Uniones (el tipo de memoria compartida C ++) en C # puro, seguro

    Sin recurrir a modos y punteros inseguros, puede hacer que los miembros de la clase compartan espacio de memoria en una clase / estructura. Dada la siguiente clase:

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

    Puede modificar los valores de los campos de bytes manipulando el campo Int32 y viceversa. Por ejemplo, este progtwig:

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

    Salidas esto:

     2147483647 FF FF FF 7F 65535 

    solo agregue usando System.Runtime.InteropServices;

    Usando @ para nombres de variables que son palabras clave.

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

    Si desea salir de su progtwig sin llamar a ningún bloque o finalizador finalmente use FailFast :

     Environment.FailFast() 

    Devolver tipos anónimos desde un método y acceder a miembros sin reflexión.

     // 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 classes, 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;