¿Características ocultas de C #? [cerrado]

1475

Esto vino a mi mente después de aprender 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 genéricos , tipos anónimos , lambdas , LINQ , ...

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

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


Palabras clave

Atributos

Sintaxis

  • ??(fusionar nulos) operador de kokos
  • Banderines de números de Nick Berardi
  • where T:newpor Lars Mæhlum
  • Genéricos implícitos por Keith
  • Lambdas de un parámetro de Keith
  • Auto propiedades de Keith
  • Alias ​​de espacio de nombres de Keith
  • Literales de cadena literales con @ by Patrick
  • enumvalores por lfoust
  • @variablenames por marxidad
  • eventoperadores por marxidad
  • Formatear corchetes por Portman
  • Modificadores de accesibilidad de acceso de propiedad por xanadont
  • Operador condicional (ternario) ( ?:) por JasonS
  • checkedy uncheckedoperadores de Binoj Antony
  • implicit and explicitoperadores de Flory

Características del lenguaje

Características de Visual Studio

Marco de referencia

Métodos y propiedades

consejos y trucos

  • Buen método para controladores 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 colección de Will
  • Funciones en línea anónimas similares a JavaScript de roosteronacid

Otro

Serhat Ozgel
fuente

Respuestas:

752

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ía. 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;
ageektrapped
fuente
584

Las lambdas y la inferencia de tipos están infravaloradas. Las lambdas pueden tener múltiples declaraciones y duplican automáticamente como un objeto delegado compatible (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 new CancellationEventHandlerni tengo que especificar tipos desender y e, son infecibles desde el evento. Es por eso que esto es menos engorroso para escribir todo, lo delegate (blah blah)que también requiere que especifique tipos de parámetros.

Las lambdas no necesitan devolver nada y la inferencia de tipos es extremadamente poderosa en un contexto como este.

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

Tenga en cuenta 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 la otra cosa fundamental que debes aprender :-)

chakrit
fuente
528

De Rick Strahl :

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

string result = value1 ?? value2 ?? value3 ?? String.Empty;
revs jfs
fuente
454

Genéricos con alias:

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

Te permite usar ASimpleName, en lugar deDictionary<string, Dictionary<string, List<string>>> .

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

BlackTigerX
fuente
438

Desde CLR a través de C # :

Al normalizar cadenas, se recomienda que use 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 cambiaba las cadenas a mayúsculas antes de comparar. Siempre me he preguntado por qué lo hace porque siento que es más "natural" convertir a minúsculas primero. Después de leer el libro ahora sé por qué.

jfs
fuente
254
Cuando "convierte una cadena en mayúsculas", crea un segundo objeto de cadena temporal. Pensé que este tipo de comparación no era preferible, que la mejor manera era: String.Equals (stringA, stringB, StringComparison.CurrentCultureIgnoreCase) que no crea esta cadena desechable en absoluto.
Anthony
32
¿Qué tipo de optimización puede realizar al comparar cadenas en mayúsculas que no se pueden hacer en cadenas en minúsculas? No entiendo por qué uno sería más óptimo que el otro.
Parappa
36
La conversión a mayúsculas en lugar de minúsculas también puede evitar un comportamiento incorrecto en ciertas culturas. Por ejemplo, en turco, dos i's en minúscula se asignan al mismo I. en mayúscula Google "i turco" para más detalles.
Neil
34
Intenté comparar ToUpperInvariant vs ToLowerInvariant. No puedo encontrar ninguna diferencia en su rendimiento bajo .NET 2.0 o 3.5. Ciertamente, no hay nada que justifique "altamente recomendado" usar uno sobre el otro.
Rasmus Faber
19
Se prefiere ToUpperInvariant porque hace que todos los caracteres sean de ida y vuelta. Ver msdn.microsoft.com/en-us/library/bb386042.aspx . Para las comparaciones, escriba"a".Equals("A", StringComparison.OrdinalIgnoreCase)
SLaks
408

Mi truco favorito es utilizar el operador de fusión nula y los paréntesis para crear instancias automáticas de colecciones para mí.

private IList<Foo> _foo;

public IList<Foo> ListOfFoo 
    { get { return _foo ?? (_foo = new List<Foo>()); } }
Will
fuente
23
¿No te resulta difícil de leer?
Riri
72
Es un poco difícil de leer para el no ... er, inexperto. Pero es compacto y contiene un par de patrones y características de lenguaje que el programador debe conocer y comprender. Entonces, si bien es difícil al principio, proporciona el beneficio de ser una razón para aprender.
38
La instanciación perezosa es algo de mala práctica porque es una mala elección del hombre evitar pensar en invariantes de clase. También tiene problemas de concurrencia.
John Leidegren
17
Siempre me han informado que esta es una mala práctica, que llamar a una propiedad no debería hacer algo como tal. Si tuviera un conjunto allí y estableciera el valor en nulo, sería muy extraño que alguien use su API.
Ian
8
@Joel, excepto que establecer ListOfFoo en nulo no es parte del contrato de clase ni es una buena práctica. Por eso no hay un setter. También es por qué ListOfFoo está garantizado para devolver una colección y nunca una nula. Es una queja muy extraña que si haces dos cosas malas (haces un setter y configuras una colección como nula), esto hará que tus expectativas sean incorrectas. Tampoco sugeriría hacer Environment.Exit () en el getter. Pero eso tampoco tiene nada que ver con esta respuesta.
315

Evite buscar controladores de eventos nulos

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

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

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

cero
fuente
87
Creo que aparecerá un problema si confía en esta técnica y luego tiene que serializar la clase. Eliminará el evento y luego, en la deserialización, obtendrá una NullRefference ... Así que uno puede apegarse a la "vieja forma" de hacer las cosas. Es más seguro.
sirrocco
16
aún puede configurar su controlador de eventos en nulo, por lo que aún puede obtener una referencia nula y aún tiene una condición de carrera.
Robert Paulson
64
Una prueba de perfil rápida muestra que el controlador de eventos con suscripción ficticia sin prueba nula demora aproximadamente el doble del tiempo que el controlador de eventos sin suscripción con prueba nula. El controlador de eventos de multidifusión sin prueba nula tarda aproximadamente 3,5 veces el tiempo del controlador de eventos de difusión única con prueba nula.
P Daddy
54
Esto evita la necesidad de una verificación nula al tener siempre un auto suscriptor. Incluso como un evento vacío, esto conlleva una sobrecarga que no desea. Si no hay suscriptores que no desea activar el evento, no siempre active primero un evento ficticio vacío. Consideraría este mal código.
Keith
56
Esta es una sugerencia terrible, por las razones en los comentarios anteriores. Si debe hacer que su código se vea "limpio", use un método de extensión para verificar si es nulo y luego llame al evento. Alguien con privilegios de modificación definitivamente debe agregar los inconvenientes a esta respuesta.
Greg
305

Todo lo demás, más

1) genéricos implícitos (¿por qué solo en métodos y no en 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 e 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 particular):

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

web::Control aWebControl = new web::Control();
win::Control aFormControl = new win::Control();
Keith
fuente
14
en # 3 puedes hacer Enumerable.Range (1,5)
Echostorm
18
Creo que ha podido inicializar matrices con int [] nums = {1,2,3}; desde 1.0 :) ni siquiera necesita la palabra clave "nueva"
Lucas
13
también lambda sin parámetros () => DoSomething ();
Pablo Retyk
55
He usado ambos {get; conjunto interno; } y obten; conjunto protegido; }, entonces este patrón es consistente.
Keith
77
@Kirk Broadhurst, tienes razón, new web.Control()también funcionaría en este ejemplo. La ::sintaxis lo obliga a tratar el prefijo como un alias de espacio de nombres, por lo que podría tener una clase llamada weby la web::Controlsintaxis aún funcionaría, mientras que la web.Controlsintaxis no sabría si verificar la clase o el espacio de nombres. Debido a eso, tiendo a usar siempre ::cuando hago alias de espacios de nombres.
Keith
286

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

MyClass myObject = (MyClass) obj;

vs

MyClass myObject = obj as MyClass;

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

Mike Stone
fuente
42
Sin embargo, no lo hagas en exceso. Parece que muchas personas lo usan porque prefieren la sintaxis a pesar de que desean la semántica de a (ToType) x.
Scott Langham
44
No creo que ofrezca un mejor rendimiento. ¿Lo has perfilado? (Obviamente, lo hace cuando falla el lanzamiento ... pero cuando usas el lanzamiento (MyClass), las fallas son excepcionales ... y extremadamente raras (si es que ocurren), así que no hay diferencia.
Scott Langham
77
Esto es solo más eficaz si el caso habitual es el fallo del reparto. De lo contrario, el objeto de conversión directa (tipo) es más rápido. Sin embargo, a un lanzamiento directo le lleva más tiempo lanzar una excepción que devolver nulo.
Spence
15
Justo en la misma línea de la palabra clave "como" ... la palabra clave "es" es igual de útil.
dkpatt
28
Puede abusar de él y tener una NullReferenceException más adelante cuando podría haber tenido una InvalidCastException antes.
Andrei Rînea
262

Dos cosas que me gustan son las propiedades automáticas para que pueda colapsar aún más su código:

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

se convierte

public string Name { get; set;}

También objetos inicializadores:

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

se convierte

Employee emp = new Employee {Name="John Smith", StartDate=DateTime.Now()}
lomaxx
fuente
66
¿Debe tenerse en cuenta que las Propiedades automáticas son una característica exclusiva de C # 3.0?
Jared Updike
21
Las propiedades automáticas se introdujeron con el compilador 3.0. Pero dado que el compilador se puede configurar para generar código 2.0, funcionan bien. ¡Simplemente no intente compilar código 2.0 con propiedades automáticas en un compilador anterior!
Joshua Shannon
74
Algo que muchas personas no se dan cuenta es que get and set puede tener accesibilidad diferente, por ejemplo: public string Name {get; set privado;}
Nader Shirazie
77
El único problema con las propiedades automáticas es que no parece posible proporcionar un valor de inicialización predeterminado.
Stein Åsmul
77
@ANeves: no, no lo es. Desde esa página: Un DefaultValueAttribute no hará que un miembro se inicialice automáticamente con el valor del atributo. Debe establecer el valor inicial en su código. [DefaultValue]se usa para el diseñador para que sepa si se debe mostrar una propiedad en negrita (es decir, no predeterminada).
Roger Lipscombe
255

La palabra clave 'predeterminada' 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.

Eric Minkes
fuente
44
Plus: tipo? como acceso directo para Nullable <type>. default (int) == 0, pero default (int?) == nulo.
sunside
221

El @ 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
lomaxx
fuente
¿No incluiría la cadena todos los espacios que usó para la sangría?
Andy
18
Sí, se llama cadena literal.
Joan Venge
44
Sería más claro si la salida mostrara los espacios que también se imprimirían. En este momento parece que las nuevas líneas de caracteres se imprimen pero los espacios se ignoran.
aleemb
Muy útil para escapar de expresiones regulares y largas consultas SQL.
cenizas999
También se asigna {{a {y }}para }que sea útil para string.Format().
Ferruccio
220

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 las bibliotecas más nuevas como NInject y Moq están utilizando.

Por ejemplo, supongamos 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 tipeo fuerte. ¿Qué sucede si cambio el nombre de "SomeMethod"? Ahora, en 3.5, sin embargo, puedo hacer esto de una manera muy tipada:

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

En el que la clase RegisterMethod usa Expression<Action<T>>así:

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 gran razón por la que estoy enamorado de Lambdas y Expression Trees en este momento.

Jason Olson
fuente
3
Tengo una clase de utilidad de reflexión que hace lo mismo con FieldInfo, PropertyInfo, etc ...
Olmo
Si, esto es genial. Pude usar métodos como este para escribir código como EditValue(someEmployee, e => e.FirstName);en mi lógica de negocios y hacer que genere automáticamente toda la lógica de plomería para un ViewModel y View para editar esa propiedad (por lo tanto, una etiqueta con el texto "Nombre" y un TextBox con un enlace que llama al configurador de la propiedad FirstName cuando el usuario edita el nombre y actualiza la Vista usando el captador). Esta parece ser la base de la mayoría de las nuevas DSL internas en C #.
Scott Whitlock, el
44
Creo que estos no son tanto menos conocidos como menos entendidos.
Justin Morgan
¿Por qué necesitas registrar un método? Nunca he usado esto antes: ¿dónde y cuándo se usaría?
MoonKnight
209

" ceder " vendría a mi mente. Algunos de los atributos como [DefaultValue ()] también se encuentran entre mis favoritos.

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

Editar: kokos, gracias por señalar el ?? operador, eso es realmente muy útil. Dado que es un poco difícil de google (ya que ?? simplemente se ignora), aquí está la página de documentación de MSDN para ese operador: ?? Operador (Referencia de C #)

Michael Stum
fuente
14
La documentación del valor predeterminado dice que en realidad no está configurando el valor de la propiedad. Es solo una ayuda para visualizadores y generadores de código.
Boris Callens
2
En cuanto a DefaultValue: Mientras tanto, algunas bibliotecas lo usan. ASP.net MVC usa DefaultValue en los parámetros de una acción del controlador (que es muy útil para los tipos no anulables). Hablando estrictamente, por supuesto, este es un generador de código ya que el valor no lo establece el compilador sino el código de MVC.
Michael Stum
66
El nombre de la ?? operador es el operador "Null Coalescing"
Armstrongest
el rendimiento es mi favorito, aunque el operador de fusión está ahí arriba. No veo nada sobre CAS, o la firma de ensamblados, nombres seguros, el GAC ... Supongo que solo CAS es C # ... pero muchos desarrolladores no tienen idea de la seguridad.
BrainSlugs83
198

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

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

Brad Barker
fuente
1
DateTime no se puede establecer en nulo.
Jason Jackson
2
Entonces, ¿es "int" solo azúcar sintáctico C # para System.Int32? En realidad, el soporte del compilador se basa en los tipos Nullable, lo que permite configurarlos como nulos, por ejemplo (que no se puede hacer usando estructuras genéricas solas) y encuadrarlos como su tipo subyacente.
P Papi
44
@P Daddy: sí, int es azúcar sintáctico para System.Int32. Son completamente intercambiables, al igual que int? === Int32? === Nullable <Int32> === Nullable <int>
cjk
66
@ck: Sí, int es un alias para System.Int32, como T? es un alias para Nullable <T>, pero no es solo azúcar sintáctico. Es una parte definida del lenguaje. Los alias no solo hacen que el código sea más fácil de leer, sino que también se ajustan mejor a nuestro modelo. ¿Expresando Nullable <Doble> como doble? subraya la perspectiva de que el valor así contenido es (o puede ser) un doble, no solo una estructura genérica instanciada en el tipo Double. (continuación)
P Daddy
3
... En cualquier caso, el argumento no era sobre alias (supongo que era una analogía pobre, supongo), sino que los tipos anulables (usando la sintaxis que prefiera) son de hecho una característica del lenguaje, no solo un producto de genéricos. No puede reproducir toda la funcionalidad de los valores nulables (comparación / asignación de nulo, reenvío de operador, boxeo de tipo subyacente o nulo, compatibilidad con fusión y asoperadores nulos ) solo con genéricos. <T> anulable solo es rudimentario y está lejos de ser estelar, pero el concepto de tipos anulables como parte del lenguaje es increíble.
P Daddy
193

Estas son algunas características interesantes ocultas 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 / unboxing más eficiente antes de los genéricos. Trabajan en coordinación con la estructura System.TypedReference.

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 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 retorno de rendimiento. No está realmente oculto, pero mucha gente no lo sabe. LINQ está construido sobre esto; permite consultas ejecutadas con retraso al generar una máquina de estado bajo el capó. Raymond Chen recientemente publicó sobre los detalles internos y arenosos .

Judá Himango
fuente
2
Más detalles sobre las palabras clave indocumentadas por Peter Bromberg . Todavía no entiendo si hay razones para usarlos alguna vez.
HuBeZa
@HuBeZa con el advenimiento de los genéricos, no hay muchas (¿alguna?) Buenas razones para usar __refType, __makeref y __refvalue. Estos se usaron principalmente para evitar el boxeo antes de los genéricos en .NET 2.
Judah Gabriel Himango
Matt, con la introducción de genéricos en .NET 2, hay pocas razones para usar estas palabras clave, ya que su propósito era evitar el boxeo cuando se trata de tipos de valor. Vea el enlace de HuBeZa, y también vea codeproject.com/Articles/38695/UnCommon-C-keywords-A-Look#ud
Judah Gabriel Himango
185

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

Sin recurrir al modo inseguro y 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);
    }

Salidas esto:

2147483647
FF FF FF 7F
65535

simplemente agregue usando System.Runtime.InteropServices;

ZeroBugBounce
fuente
77
@George, hace maravillas cuando te comunicas con aplicaciones heredadas a través de sockets mediante declaraciones de unión c.
scottm
2
También es significativo decir int y float en el desplazamiento 0. Es lo que necesita si desea manipular números de coma flotante como máscaras de bits, lo que a veces desea. Especialmente si quieres aprender cosas nuevas sobre números de coma flotante.
John Leidegren
2
Lo molesto de esto es que si vas a usar esto es una estructura, el compilador te obligará a establecer TODAS las variables en la función init. Entonces, si tiene: public A (int int32) {Int32 = int32; } arrojará "El campo 'Uno' debe estar completamente asignado antes de devolver el control a la persona que llama", por lo que debe configurar Uno = Dos = Tres = Cuatro = 0; también.
manixrock 01 de
2
Esto tiene sus usos, principalmente con datos binarios. Utilizo una estructura "Pixel" con un int32 @ 0, y cuatro bytes para los cuatro componentes @ 0, 1, 2 y 3. Excelente para manipular datos de imágenes de forma rápida y fácil.
snarf
57
Advertencia: este enfoque no tiene en cuenta la endianidad. Eso significa que su código C # no se ejecutará de la misma manera en todas las máquinas. En las CPU little-endian (que almacenan primero el byte menos significativo), se utilizará el comportamiento mostrado. Pero en las CPU big-endian, los bytes saldrán invertidos de lo que esperaba. Tenga cuidado con cómo usa esto en el código de producción: su código puede no ser portátil para ciertos dispositivos móviles y otro hardware, y puede romperse de maneras no obvias (por ejemplo, dos archivos aparentemente en el mismo formato pero en realidad con orden de bytes invertido).
Ray Burns
176

Usando @ para nombres de variables que son palabras clave.

var @object = new object();
var @string = "";
var @if = IpsoFacto(); 
Mark Cidade
fuente
38
¿Por qué querrías usar una palabra clave como nombre de variable? Me parece que esto haría que el código fuera menos legible y ofuscado.
Jon
41
Bueno, la razón por la que existe es que la CLI lo requiere para la interoperabilidad con otros lenguajes que podrían usar palabras clave de C # como nombres de miembros
Mark Cidade
69
Si alguna vez quisiste usar los ayudantes de asp.net MVC HTML y definir una clase HTML, te alegrará saber que puedes usar @class para que no sea reconocida como la palabra clave de la clase
Boris Callens,
31
Ideal para métodos de extensión. público estático vacío DoSomething (este Bar @this, string foo) {...}
Jonathan C Dickinson el
45
@zihotki: Mal. var a = 5; Console.WriteLine (@a); Imprime 5
SLaks
168

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

Environment.FailFast()
Jan Bannister
fuente
12
Tenga en cuenta que este método también crea un volcado de memoria y escribe un mensaje en el registro de errores de Windows.
RickNZ
1
Cabe señalar que no se
llamarán
1
+1 para la pista, pero esto no es C #, es BCL de .NET.
Abel
System.Diagnostics.Process.GetCurrentProcess (). Kill () es más rápido
Tolgahan Albayrak
153

Devolver tipos anónimos de 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<T>(object obj, T t)
{
   return (T) obj;
}
denis phillips
fuente
42
Eso realmente no te da nada. En realidad es peligroso. ¿Qué sucede si GetUserTuple se modifica para devolver varios tipos? El lanzamiento fallará en tiempo de ejecución. Una de las mejores cosas de C # /. Net es la comprobación del tiempo de compilación. Sería mucho mejor simplemente crear un nuevo tipo.
Jason Jackson
99
@ Jason Dije que probablemente no sea útil, pero es sorprendente (y pensé que estaba oculto).
denis phillips
31
Si bien es genial, esto parece una elección de diseño bastante pobre. Básicamente has definido el tipo anónimo en dos lugares. En ese punto, simplemente declare una estructura real y úsela directamente.
Paul Alexander
66
@George: tal convención se llamaría ... ¿estructura?
R. Martinho Fernandes
2
Este truco se llama 'emitir por muestra' y no funcionará si el método que devuelve el tipo anónimo se encuentra en otro ensamblado.
desco
146

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

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

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

Patrick
fuente
27
Además, una constante @ acepta nuevas líneas dentro. Perfecto al asignar un script multilínea a una cadena.
Tor Haugen el
11
No se olvide también de escapar de una comilla, simplemente duplíquelas, en otras palabras. [code] var candy = @ "Me gusta" "rojo" "bastones de caramelo"; [/ code]
Dave
55
Tiendo a construir caminos con Path.Combine. ¡Definitivamente uso la @ para expresiones regulares!
Dan McClain
66
@new es también una variable en lugar de una palabra clave: @este, @int, @return, @interface ... etc :)
iAbstract
Este no se acerca: ¿Pero cuáles son las características o trucos más ocultos de C # que incluso los fanáticos de C #, los adictos y los expertos apenas conocen?
publicgk
141

Mixins Básicamente, si desea agregar una función a varias clases, pero no puede usar una clase base para todas ellas, haga que cada clase implemente una interfaz (sin miembros). Luego, escriba 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!

Dmitri Nesteruk
fuente
44
Sí, creo que este es el verdadero poder de los métodos de extensión. Básicamente permiten implementaciones de métodos de interfaz.
John Bubriski
Esto también es útil si está usando NHibernate (o Castle ActiveRecord) y tiene que usar interfaces para sus colecciones. De esta manera puede dar comportamiento a las interfaces de colección.
Ryan Lundy
Así es básicamente cómo se implementan todos los métodos LINQ, para el registro.
WCWedin
Aquí hay un enlace que habla sobre lo que mencioné
Ryan Lundy
77
¡Si solo permitieran propiedades de extensión! Odiaba tener que escribir un método de extensión que comenzaba a ser una propiedad de solo lectura ... "
John Gibb
130

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

¿Verdadero, falso, FileNotFound ?

Michael Stum
fuente
87
si se espera que un usuario responda un sí, no una pregunta, entonces nulo sería apropiado si la pregunta no ha sido respondida
Omar Kooheji
22
Los tipos anulables son útiles para la interacción con una base de datos donde las columnas de la tabla a menudo son anulables.
tuinstoel 01 de
11
Si, no, quizas?
Dan Blair
21
Almacenar los valores de un ThreeState CheckBox
Shimmy Weitzhandler el
8
Como en SQL: Sí / no / desconocido.
erikkallen
116

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

Se presta mucha atención a los algoritmos "mapa", "reducir" y "filtro". De 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 SQL, basados ​​en el hecho de que son parte de LINQ.

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

"reduce" =>
Agregar valores agregados en un solo resultado

"filter" => Donde
filtra datos basados ​​en 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.

Brad Wilson
fuente
1
Seleccionar también actúa como la función "retorno" en mónadas. Ver stackoverflow.com/questions/9033/hidden-features-of-c#405088
Mark Cidade el
1
Usar "select" solo es necesario si usa la sintaxis SQLish. Si usa la sintaxis del método de extensión - someCollection.Where (item => item.Price> 5.99M) - no se requiere el uso de sentencias select.
Brad Wilson
77
@Brad, eso (donde) es una operación de filtro. Trate de hacer una operación de selección de mapa sin ...
Eloff
2
LINQ es lo más importante que le sucedió a C # en mi opinión: stackoverflow.com/questions/2398818/…
Leniel Maccaferri
1
La firma más pequeña de Aggregate es la función "reducir", la firma central de Aggregate es la función "doblar" mucho más potente.
Brett Widmeier
115
Environment.NewLine

para líneas nuevas independientes del sistema.

nt.
fuente
10
Lo molesto de este es que no está incluido en el marco compacto.
Stormenet
14
Vale la pena señalar que esto es específico para la plataforma host de la aplicación, por lo que si está creando datos destinados a otro sistema, debe usar \ n o \ r \ n de manera adecuada.
Mesh
Esto es parte del BCL de .NET, no una característica de C # per se.
Abel
111

Si está tratando de usar corchetes 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"
Portman
fuente
19
@ Kyralessa: En realidad, sí, son llaves, pero "llaves" es un nombre alternativo para ellas. [y ]son corchetes, <y >son corchetes angulares. Ver en.wikipedia.org/wiki/Bracket .
icktoofay
44
Estás en lo correcto. Pero cuando comenté, no decía corchetes "rizados".
Ryan Lundy
2
Muy agradable para señalar. Recuerde que mi primer String.Format tenía el siguiente aspecto: String.Format ("{0} Estoy entre llaves {1} {2} {3}", "{", "}", 3, "ratones ciegos"); Una vez que descubrí que escapar de estos se hace usando {{y}} estaba tan feliz :)
Gertjan
Muahahahaa ... Programando ya 3 años en .Net y no sabía este. : D
Arnis Lapsa
paréntesis "rizados" que actúan de forma similar a las secuencias de escape?
Pratik
104
  1. ?? - operador coalescente
  2. utilizando ( instrucción / directiva ): excelente palabra clave que se puede usar para algo más que simplemente llamar a Eliminar
  3. solo lectura - debe usarse más
  4. netmodules: lástima que no haya soporte en Visual Studio
Doctor Jones
fuente
66
using también se puede usar para crear un alias de un espacio de nombres largo en una cadena más conveniente, es decir: using ZipEncode = MyCompany.UtilityCode.Compression.Zip.Encoding; Hay más aquí: msdn.microsoft.com/en-us/library/sf0df423.aspx
Dave R.
2
Realmente no es lo mismo. Al llamar a Dispose, puede usar la instrucción using, cuando aliasing tipos está usando una directiva using.
Øyvind Skaar
2
En caso de que desee un nombre para # 1 (como lo hizo con el operador ternario), ?? se llama operador de fusión nulo.
J. Steen
44
@LucasAardvark: Como J Steen mencionó, se llama operador de fusión nula. ¡Busca eso!
kokos
1
Buscar ?? operador en google try: google.com/search?q=c%23+%3F%3F+operator
barra invertida17
103

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

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

Si vas a usar 'es', ¿por qué seguir con un molde seguro usando 'como'? Si ha comprobado que obj es de hecho MyClass, un elenco de pantano estándar:

c = (MyClass)obj

... nunca va a fallar.

Del mismo modo, podrías 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 tipos a un máximo de uno. Es poco probable que rompa el banco de procesamiento de cualquier manera; personalmente, creo que la última forma también se ve más limpia.

Dogmang
fuente
16
Si el lanzamiento es del tipo exacto (lanzado a "A" cuando el objeto es "A", no derivado de él), el lanzamiento directo es ~ 3x MÁS RÁPIDO que "como". Al lanzar un tipo derivado (lanzar a "A" cuando el objeto es "B", que se deriva de "A"), el lanzamiento directo es ~ 0.1x más lento que "como". "es", luego "como" es una tontería.
P Daddy
2
No, pero podría escribir "if ((c = obj as MyClass)! = Null)".
Dave Van den Eynde el
10
isy asno hará lanzamientos de usuarios. Entonces, el código anterior pregunta con el isoperador si obj se deriva de MyClass (o si tiene un reparto definido implícito en el sistema). Además, isfalla null. Ambos casos extremos pueden ser importantes para su código. Por ejemplo, es posible que desee escribir: if( obj == null || obj is MyClass ) c = (MyClass)obj; Pero esto es estrictamente diferente de: try { c = (MyClass)obj; } catch { }dado que el primero no realizará ninguna conversión definida por el usuario, pero el segundo sí. Sin el nullcheque, el primero tampoco se establecerá ccuando objsea null.
Adam Luter
2
En IL, un elenco va a un CASTCLASS pero un as / is va a una instrucción ISINST.
John Gibb
55
Corrí una prueba para esto, fundición IEnumerable<int>a List<int>, y la fundición object( new object()) que IEnumerable<int>, para asegurarse de que no hay errores: fundición directa: 5.43ns, es-> como elenco: 6.75ns, como reparto: 5.69ns. Luego, prueba de lanzamientos no válidos: lanzamiento directo: 3125000ns, como lanzamiento: 5.41ns. Conclusión: deja de preocuparte por el factor 1% y solo asegúrate de usar is / as cuando el lanzamiento podría no ser válido, porque las excepciones (también si se manejan) son MUY lentas en comparación con el lanzamiento, estamos hablando de un factor 578000 más lento. Recuerde que la última parte, el resto no importa (.Net FW 4.0, versión de lanzamiento)
Aidiakapi
98

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

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

se puede condensar a:

x = (x==1) ? 2 : 3;
JasonS
fuente
10
El operador ternario ha sido prohibido en mi grupo. A algunas personas simplemente no les gusta, aunque nunca he entendido por qué.
Justin R.
13
Supongo que porque no son las mismas cosas, ser un operador no una declaración. Prefiero el primer acercamiento yo mismo. Es más consistente y fácilmente expandible. Los operadores no pueden contener declaraciones, por lo que en el momento en que tiene que expandir el cuerpo, tendrá que convertir ese operador ternario en una declaración if
Kervin
16
se puede condensar a x ++; Ok, no tiene sentido ^^
François
55
@Guillaume: Para tener en cuenta todos los valores de x: x = 2 + System.Math.Min (1, System.Math.Abs ​​(x-1));
mbeckish
38
En realidad se llama el "operador condicional", es un operador ternario porque toma tres argumentos. en.wikipedia.org/wiki/Conditional_operator
Blorgbeard saldrá el