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
-
yield
de Michael Stum -
var
por Michael Stum -
using()
declaraciónusing()
de kokos -
readonly
por kokos -
as
por Mike Stone -
as
/is
por Ed Swangren -
as
/is
(mejorado) por Rocketpants -
default
por deathofrats -
global::
por pzycoman -
using()
bloques por AlexCuse -
volatile
por Jakub Šturc -
extern alias
por Jakub Šturc
Atributos
-
DefaultValueAttribute
por Michael Stum -
ObsoleteAttribute
por DannySmurf -
DebuggerDisplayAttribute
by Stu -
DebuggerBrowsable
andDebuggerStepThrough
by bdukes -
ThreadStaticAttribute
por marxidad -
FlagsAttribute
de Martin Clarke -
ConditionalAttribute
por AndrewBurns
Sintaxis
-
??
(coalesce nulls) operator by kokos - Número de mallas por Nick Berardi
-
where T:new
por Lars Mæhlum - Genéricos implícitos por Keith
- Las lambdas de un parámetro de Keith
- Propiedades de auto por Keith
- Alias de espacios de nombres por Keith
- Literales de cuerdas verbales con @ by Patrick
-
enum
valores por lfoust - @variablenames by marxidad
- Operadores de
event
por marxidad - Formato entre corchetes de Portman
- Propiedad de xanadont modificadores de accesibilidad por xanadont
- Operador condicional (ternario) (
?:
JasonS Por JasonS - Operadores
checked
yunchecked
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 - Inicializadores de objetos por lomaxx
- Formato de cuerdas de David en Dakota
- Métodos de extensión por marxidad
- métodos
partial
por Jon Erickson - Directivas de preprocesador por John Asbeck
- Directiva de preprocesador
DEBUG
por Robert Durgin - Sobrecarga del operador por SefBkn
- Escriba inferrence por chakrit
- Rob Gough lleva a los operadores booleanos al siguiente nivel
- Pasa la variable de tipo de valor como interfaz sin boxeo por Roman Boiko
- Determinar programáticamente el tipo de variable declarada por Roman Boiko
- Constructores estáticos por Chris
- Mapeo de ORM más fácil de usar / condensado usando LINQ by roosteronacid
-
__arglist
por Zac Bowling
Características de Visual Studio
- Selecciona bloque de texto en editor por Himadri
- Fragmentos de DannySmurf
Marco de referencia
-
TransactionScope
de KiwiBastard -
DependantTransaction
por KiwiBastard -
Nullable<T>
por IainMH -
Mutex
de Diago -
System.IO.Path
por ageektrapped -
WeakReference
de Juan Manuel
Métodos y propiedades
-
String.IsNullOrEmpty()
de KiwiBastard -
List.ForEach()
de KiwiBastard -
BeginInvoke()
,EndInvoke()
por Will Dean -
Nullable<T>.HasValue
yNullable<T>.Value
properties by Rismo - Método
GetValueOrDefault
por John Sheehan
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
- netmodules por kokos
- LINQBridge por Duncan Smart
- Extensiones paralelas por Joel Coehoorn
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 ?
" 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 .
Atributos en general, pero sobre todo DebuggerDisplay . Te ahorra años.
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.