versiones sintaxis programar programacion lenguaje introduccion elementos documentacion comandos caracteristicas c# hidden-features

sintaxis - Características ocultas de C#?



sintaxis c# (30)

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 que una vez mi compañero de trabajo siempre cambiaba las cadenas a mayúsculas antes de comparar. Siempre me he preguntado por qué lo hace porque creo que es más "natural" convertirse primero a minúsculas. Después de leer el libro ahora sé por qué.

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

where T : struct

Nosotros, los desarrolladores de C #, todos sabemos lo básico 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 funciones o los trucos más ocultos de C # que incluso los fanáticos de C #, los adictos y los expertos apenas conocen?

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


Palabras clave

Atributos

Sintaxis

Características del lenguaje

Características de Visual Studio

Marco de referencia

Métodos y propiedades

consejos y trucos

  • Buen método para manejadores de eventos por Andreas HR Nilsson
  • Comparaciones mayúsculas de John
  • Accede 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 de JavaScript por roosteronacid

Otro


La @ le dice al compilador 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 compilador 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


Sin embargo, no estoy seguro de por qué alguien querría usar Nullable <bool>. :-)

Verdadero, Falso, FileNotFound ?


  1. ?? - operador coalescente
  2. Uso de ( statement / directive ): gran palabra clave que se puede usar para más que solo llamar a Dispose
  3. readonly - debería ser usado más
  4. Netmodules: muy mal, no hay soporte en Visual Studio

" yield " vendría a mi mente. Algunos de los atributos como DefaultValueAttribute también están entre mis favoritos.

La palabra clave " var " es un poco más conocida, pero puede usarla también en las aplicaciones .NET 2.0 (siempre que use el compilador .NET 3.5 y la configure en el código de salida 2.0) no parece ser muy conocida. bien.

Edit: kokos, gracias por señalar el ?? Operador, eso es realmente muy útil. Ya que es un poco difícil buscarlo en Google (ya que se ignora), aquí está la página de documentación de MSDN para ese operador: ??


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

__makeref __reftype __refvalue __arglist

Estas son palabras clave de C # no documentadas (¡incluso Visual Studio las reconoce!) Que se agregaron para un boxeo / desempaquetado más eficiente antes de los genéricos. Trabajan en coordinación con la estructura System.TypedReference.

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

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

La característica "oculta" más útil sería la palabra clave de rendimiento de rendimiento. No está realmente oculto, pero mucha gente no lo sabe. LINQ se construye encima de esto; permite realizar consultas con demora generando una máquina de estado debajo del capó. Raymond Chen publicó recientemente sobre los detalles internos y valientes .



Creo que una de las características menos apreciadas y menos conocidas de C # (.NET 3.5) son los Árboles de Expresión , especialmente cuando se combinan con Genéricos y Lambdas. Este es un enfoque para la creación de API que están utilizando las bibliotecas más nuevas como NInject y Moq.

Por ejemplo, digamos que quiero registrar un método con una API y que la 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 en cadenas):

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

Bueno, eso apesta por la falta de escritura fuerte. ¿Qué pasa si cambio el nombre de "SomeMethod"? Ahora, en 3.5, sin embargo, puedo hacer esto de una manera muy tipográfica:

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

En el que la clase RegisterMethod usa Expression<Action<T>> siguiente manera:

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

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


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;


Dos cosas que me gustan son las propiedades automáticas para que puedas contraer tu código aún más:

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

se convierte en

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 en

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


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;


Genéricos con alias:

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

Le permite usar ASimpleName , en lugar de Dictionary<string, Dictionary<string, List<string>>> .

Úselo cuando usaría la misma cosa grande, genérica, larga y compleja en muchos lugares.


La palabra clave ''por defecto'' en tipos genéricos:

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.


Mi truco favorito es usar el operador de unión nula y los paréntesis para crear instancias automágicamente para mí.

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


No sabía la palabra clave "como" durante bastante tiempo.

MyClass myObject = (MyClass) obj;

vs

MyClass myObject = obj as MyClass;

El segundo devolverá el valor nulo si obj no es una MyClass, en lugar de lanzar una excepción de conversión de clase.


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

Environment.FailFast()


Tiendo a encontrar que la mayoría de los desarrolladores de C # no saben acerca de los tipos ''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();

Se devuelve String.Empty. Revisa this enlace para más detalles.


Todo lo demás, más

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

void GenericMethod<T>( T input ) { ... } //Infer type, so GenericMethod<int>(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 y inicializadores:

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

Otro:

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

public int MyId { get; private set; }

Gracias @pzycoman por recordarme:

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

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


Utilizando @ para nombres de variables que son palabras clave.

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


Evite verificar los manejadores de eventos nulos

Agregar un delegado vacío a los eventos en la declaración, suprimiendo la necesidad de verificar siempre el evento para ver si es nulo antes de llamarlo, es increíble. Ejemplo:

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

Dejar que hagas 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 esta discusión relacionada y esta publicación de blog de Eric Lippert sobre este tema (y sus posibles desventajas).


Las lambdas y las inferencias tipo están subestimadas. Lambdas puede tener varias declaraciones y se doblan como un objeto delegado compatible automáticamente (solo asegúrese de que la firma coincida) 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 , son inferables del evento. Es por eso que esto es menos engorroso para 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 tipos es extremadamente poderosa en un contexto como este.

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

Note el encadenamiento: (dx, dy) => (sender, e) =>

Ahora es por eso que estoy feliz de haber tomado la clase de programación funcional :-)

Aparte de los punteros en C, creo que es otra cosa fundamental que debes aprender :-)


Uniones (el tipo de memoria compartida de C ++) en C # pura y segura

Sin recurrir al modo inseguro ni a los punteros, 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 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); }

Produce esto:

2147483647 FF FF FF 7F 65535

solo agregue usando System.Runtime.InteropServices;


Aquí hay una útil para expresiones regulares y rutas de archivos:

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

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


Devolver tipos anónimos desde un método y acceder a los 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<T>(object obj, T t) { return (T) obj; }


Este no está "oculto" tanto como está mal llamado.

Se presta mucha atención a los algoritmos "mapa", "reducir" y "filtro". Lo que la mayoría de la gente no se da cuenta es que .NET 3.5 agregó estos tres algoritmos, pero les dio nombres muy parecidos a SQL, basándose en el hecho de que son parte de LINQ.

"map" => Seleccionar
Transforma datos de un formulario a otro

"reduce" =>
Agregue los valores de los agregados en un solo resultado

"filter" => Donde
filtra los datos según un criterio

La capacidad de usar LINQ para realizar trabajos en línea en colecciones que solían tomar iteraciones y condicionales puede ser increíblemente valiosa. Vale la pena aprender cómo todos los métodos de extensión de LINQ pueden ayudar a que su código sea mucho más compacto y fácil de mantener.


Si está intentando usar llaves dentro de una expresión 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"


Tal vez no sea una técnica avanzada, pero una que veo todo el tiempo me vuelve loca:

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

se puede condensar a

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


@Ed, soy un poco reticente a la hora de publicar esto, ya que es poco más que mezquino. Sin embargo, me gustaría señalar que en su ejemplo de código:

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

Si va a usar ''es'', ¿por qué seguirlo con un modelo seguro usando ''como''? Si has comprobado que obj es MyClass, un elenco estándar:

c = (MyClass)obj

... nunca va a fallar.

Del mismo modo, usted podría decir:

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

No sé lo suficiente sobre las entrañas de .NET para estar seguro, pero mis instintos me dicen que esto reduciría un máximo de dos operaciones de lanzamiento de tipo a un máximo. Es poco probable que se rompa el banco de procesamiento de cualquier manera; Personalmente, creo que la última forma también se ve más limpia.


Mixins. Básicamente, si desea agregar una característica a varias clases, pero no puede usar una clase base para todas ellas, haga que cada clase implemente una interfaz (sin miembros). Luego, escribe un método de extensión para la interfaz , es decir

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

Por supuesto, se sacrifica algo de claridad. ¡Pero funciona!


Environment.NewLine

Para nuevas líneas independientes del sistema.