Caratteristiche nascoste di C #? [chiuso]


1475

Questo mi è venuto in mente dopo aver appreso quanto segue da questa domanda :

where T : struct

Noi, sviluppatori di C #, conosciamo tutti le basi di C #. Intendo dichiarazioni, condizionali, loop, operatori, ecc.

Alcuni di noi hanno anche imparato cose come Generici , tipi anonimi , lambda , LINQ , ...

Ma quali sono le funzionalità o i trucchi più nascosti di C # che persino i fan di C #, i tossicodipendenti e gli esperti conoscono a malapena?

Ecco le caratteristiche rivelate finora:


parole

attributi

Sintassi

Caratteristiche del linguaggio

Funzionalità di Visual Studio

Struttura

Metodi e proprietà

Suggerimenti e trucchi

  • Bel metodo per i gestori di eventi di Andreas HR Nilsson
  • Confronti maiuscoli di John
  • Accedi a tipi anonimi senza riflessione di dp
  • Un modo rapido per istanziare pigramente le proprietà della collezione di Will
  • Funzioni in linea anonime simili a JavaScript di roosteronacid

Altro

Risposte:


752

Questo non è C # di per sé, ma non ho visto nessuno che lo usi davvero System.IO.Path.Combine()nella misura in cui dovrebbe. In effetti, l'intera classe Path è davvero utile, ma nessuno la usa!

Sono disposto a scommettere che ogni app di produzione ha il seguente codice, anche se non dovrebbe:

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

584

lambda e inferenza del tipo sono sottovalutati. Lambdas può avere più istruzioni e raddoppiano automaticamente come oggetto delegato compatibile (assicurati solo che la firma corrisponda) come in:

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

Si noti che non ho new CancellationEventHandlerné devo specificare i tipi di sendere e, sono inferibili dall'evento. Questo è il motivo per cui è meno complicato scrivere tutto, il delegate (blah blah)che richiede anche di specificare i tipi di parametri.

Le lambda non hanno bisogno di restituire nulla e l'inferenza del tipo è estremamente potente in un contesto come questo.

E a proposito, puoi sempre restituire Lambdas che rendono Lambdas nel senso della programmazione funzionale. Ad esempio, ecco un lambda che crea un lambda che gestisce 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);

Nota il concatenamento: (dx, dy) => (sender, e) =>

Ora è per questo che sono felice di aver preso la classe di programmazione funzionale :-)

A parte i puntatori in C, penso che sia l'altra cosa fondamentale che dovresti imparare :-)


528

Da Rick Strahl :

Puoi incatenare il ?? operatore in modo da poter fare un sacco di confronti null.

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

454

Generici con alias:

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

Ti permette di usare ASimpleName, invece di Dictionary<string, Dictionary<string, List<string>>>.

Usalo quando useresti la stessa cosa generica lunga e complessa in molti posti.


438

Da CLR via C # :

Quando si normalizzano le stringhe, si consiglia vivamente di utilizzare ToUpperInvariant anziché ToLowerInvariant perché Microsoft ha ottimizzato il codice per eseguire confronti maiuscoli .

Ricordo che una volta il mio collega ha sempre cambiato le stringhe in maiuscolo prima del confronto. Mi sono sempre chiesto perché lo fa perché ritengo che sia più "naturale" convertire prima in minuscolo. Dopo aver letto il libro ora so perché.


254
Quando "converti una stringa in maiuscolo" crei un secondo oggetto stringa temporaneo. Ho pensato che questo tipo di confronto non fosse preferito, che il modo migliore fosse: String.Equals (stringA, stringB, StringComparison.CurrentCultureIgnoreCase) che non crea affatto questa stringa usa e getta.
Anthony,

32
Che tipo di ottimizzazione puoi eseguire sul confronto tra stringhe maiuscole che non è possibile eseguire su stringhe minuscole? Non capisco perché uno sarebbe più ottimale dell'altro.
Parappa,

36
La conversione in maiuscolo anziché in minuscolo può anche impedire comportamenti errati in alcune culture. Ad esempio, in turco, due i minuscoli si mappano sulla stessa maiuscola I. Google "turkish i" per maggiori dettagli.
Neil,

34
Ho provato il benchmarking ToUpperInvariant vs ToLowerInvariant. Non riesco a trovare alcuna differenza nelle loro prestazioni in .NET 2.0 o 3.5. Certamente non tutto ciò che giustifica "raccomandare vivamente" di usarne uno rispetto all'altro.
Rasmus Faber,

19
ToUpperInvariant è preferito perché rende tutti i personaggi di andata e ritorno. Vedere msdn.microsoft.com/en-us/library/bb386042.aspx . Per i confronti, scrivi"a".Equals("A", StringComparison.OrdinalIgnoreCase)
SLaks

408

Il mio trucco preferito è usare l' operatore di coalescenza null e le parentesi per istanziare automagicamente le raccolte per me.

private IList<Foo> _foo;

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

23
Non trovi difficile da leggere?
Riri,

72
È leggermente difficile da leggere per il prossimo, inesperto. Ma è compatto e contiene un paio di modelli e funzionalità linguistiche che il programmatore dovrebbe conoscere e comprendere. Quindi, sebbene all'inizio sia difficile, offre il vantaggio di essere una ragione per imparare.

38
Un'istanza pigra è in qualche modo una negligenza perché è una scelta dei poveri per evitare di pensare agli invarianti di classe. Ha anche problemi di concorrenza.
John Leidegren,

17
Sono sempre stato informato che questa è una cattiva pratica, che chiamare una proprietà non dovrebbe fare qualcosa di simile. Se hai impostato un valore lì e impostato il valore su null, sarebbe molto strano per qualcuno che utilizza la tua API.
Ian,

8
@Joel tranne che l'impostazione di ListOfFoo su null non fa parte del contratto di classe né è una buona pratica. Ecco perché non c'è un setter. È anche il motivo per cui ListOfFoo è garantito per restituire una raccolta e mai un valore nullo. È solo una lamentela molto strana che se fai due cose cattive (fai un setter e setti una collezione su null) questo si tradurrà in aspettative sbagliate. Non consiglierei nemmeno di fare Environment.Exit () nel getter. Ma anche questo non ha nulla a che fare con questa risposta.

315

Evitare di controllare i gestori di eventi null

Aggiungere un delegato vuoto agli eventi durante la dichiarazione, sopprimendo la necessità di controllare sempre l'evento per null prima di chiamarlo, è fantastico. Esempio:

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

Lascialo fare

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

Invece di questo

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

Vedi anche questa discussione correlata e questo post sul blog di Eric Lippert su questo argomento (e possibili aspetti negativi).


87
Credo che apparirà un problema se fai affidamento su questa tecnica e quindi devi serializzare la classe. Eliminerai l'evento, e poi alla deserializzazione otterrai una NullRefference .... Quindi uno può semplicemente attenersi al "vecchio modo" di fare le cose. È più sicuro.
sirrocco,

16
puoi comunque impostare il gestore eventi su null, in modo da poter ottenere un riferimento null e avere ancora una condizione di competizione.
Robert Paulson,

64
Un test rapido del profilo mostra che il gestore eventi sottoscritto fittizio senza test null impiega circa il doppio del tempo del gestore eventi non sottoscritto con test null. Il gestore eventi multicast senza test null richiede circa 3,5 volte il tempo del gestore eventi singlecast con test null.
P Daddy,

54
Questo evita la necessità di un controllo nullo avendo sempre solo un auto-abbonato. Anche se un evento vuoto, questo comporta un sovraccarico che non vuoi. Se non ci sono abbonati che non si desidera attivare l'evento, non sempre attivare prima un evento fittizio vuoto. Considererei questo codice errato.
Keith il

56
Questo è un suggerimento terribile, per le ragioni dei commenti sopra. Se devi rendere il tuo codice "pulito", utilizza un metodo di estensione per verificare la presenza di null e chiama l'evento. Qualcuno con privilegi di modifica dovrebbe sicuramente aggiungere i contro a questa risposta.
Greg

305

Tutto il resto, oltre

1) generici impliciti (perché solo sui metodi e non sulle classi?)

void GenericMethod<T>( T input ) { ... }

//Infer type, so
GenericMethod<int>(23); //You don't need the <>.
GenericMethod(23);      //Is enough.

2) lambda semplici con un parametro:

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

3) tipi anonimi e inizializzatori:

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

Un altro:

4) Le proprietà automatiche possono avere ambiti diversi:

public int MyId { get; private set; }

Grazie @pzycoman per avermelo ricordato:

5) Alias ​​dello spazio dei nomi (non che tu abbia probabilmente bisogno di questa particolare distinzione):

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

web::Control aWebControl = new web::Control();
win::Control aFormControl = new win::Control();

14
nel # 3 puoi fare Enumerable.Range (1,5)
Echostorm,

18
penso che tu sia stato in grado di inizializzare le matrici con int [] nums = {1,2,3}; dall'1.0 :) non è nemmeno necessaria la "nuova" parola chiave
Lucas

13
anche lambda senza parametri () => DoSomething ();
Pablo Retyk,

5
Ho usato entrambi {get; set interno; } e prendi; set protetto; }, quindi questo modello è coerente.
Keith,

7
@Kirk Broadhurst - hai ragione - new web.Control()funzionerebbe anche in questo esempio. La ::sintassi lo costringe a trattare il prefisso come un alias dello spazio dei nomi, quindi potresti avere una classe chiamata webe la web::Controlsintassi continuerebbe a funzionare, mentre la web.Controlsintassi non saprebbe se controllare la classe o lo spazio dei nomi. Per questo motivo tendo sempre ad usare ::quando faccio alias dello spazio dei nomi.
Keith

286

Non conoscevo la parola chiave "as" da un po '.

MyClass myObject = (MyClass) obj;

vs

MyClass myObject = obj as MyClass;

Il secondo restituirà null se obj non è una MyClass, anziché generare un'eccezione di cast di classe.


42
Non esagerare però. Molte persone sembrano usare come perché preferiscono la sintassi anche se vogliono la semantica di un (ToType) x.
Scott Langham,

4
Non credo che offra prestazioni migliori. L'hai profilato? (Ovviamente lo fa anche quando il cast fallisce ... ma quando usi il cast (MyClass), i fallimenti sono eccezionali ... ed estremamente rari (se accadono affatto), quindi non fa differenza.
Scott Langham,

7
Questo è solo più performante se il solito caso è il fallimento del cast. In caso contrario, l'oggetto cast (tipo) diretto è più veloce. Ci vuole più tempo perché un cast diretto lanci un'eccezione piuttosto che restituire null.
Spence

15
Proprio lungo le stesse linee della parola chiave "as" ... la parola chiave "is" è altrettanto utile.
dkpatt,

28
Puoi abusarne e avere una NullReferenceException lungo la tua strada in seguito quando avresti potuto avere una InvalidCastException in precedenza.
Andrei Rînea,

262

Due cose che mi piacciono sono le proprietà automatiche in modo da poter comprimere ulteriormente il codice:

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

diventa

public string Name { get; set;}

Anche inizializzatori di oggetti:

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

diventa

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

6
Va notato che le proprietà automatiche sono solo una caratteristica di C # 3.0?
Jared Updike,

21
Le proprietà automatiche sono state introdotte con il compilatore 3.0. Ma poiché il compilatore può essere impostato sul codice di output 2.0, funzionano bene. Basta non provare a compilare il codice 2.0 con proprietà automatiche in un compilatore più vecchio!
Joshua Shannon,

74
Qualcosa che molte persone non capiscono è che get e set possono avere accessibilità diversa, ad esempio: stringa pubblica Nome {get; set privato;}
Nader Shirazie,

7
L'unico problema con le proprietà automatiche è che non sembra essere possibile fornire un valore di inizializzazione predefinito.
Stein Åsmul,

7
@ANeves: no non lo è. Da quella pagina: un DefaultValueAttribute non causerà l'inizializzazione automatica di un membro con il valore dell'attributo. Devi impostare il valore iniziale nel tuo codice. [DefaultValue]viene utilizzato per il designer in modo che sappia se mostrare una proprietà in grassetto (che significa non predefinito).
Roger Lipscombe,

255

La parola chiave "predefinita" in tipi generici:

T t = default(T);

genera un "null" se T è un tipo di riferimento e 0 se è un int, falso se è un valore booleano, eccetera.


4
Inoltre: digitare? come scorciatoia per Nullable <tipo>. default (int) == 0, ma default (int?) == null.
lato sole


221

@ Indica al compilatore di ignorare tutti i caratteri di escape in una stringa.

Volevo solo chiarire questo ... non gli dice di ignorare i caratteri di escape, in realtà dice al compilatore di interpretare la stringa come un valore letterale.

Se hai

string s = @"cat
             dog
             fish"

verrà effettivamente stampato come (si noti che include anche lo spazio bianco utilizzato per il rientro):

cat
             dog
             fish

la stringa non includerebbe tutti gli spazi che hai usato per il rientro?
andy,

18
Sì, si chiama stringa testuale.
Joan Venge,

4
Sarebbe più chiaro se l'output mostrasse anche gli spazi da stampare. In questo momento sembra che vengano stampati i caratteri delle nuove linee ma gli spazi vengono ignorati.
aleemb,

Molto utile per evitare espressioni regolari e lunghe query SQL.
ashes999,

Si associa anche {{ad {e }}ad }rendendolo utile per string.Format().
Ferruccio,

220

Penso che una delle funzionalità meno apprezzate e meno conosciute di C # (.NET 3.5) siano gli Expression Tree , specialmente se combinati con Generics e Lambdas. Questo è un approccio alla creazione dell'API utilizzato da librerie più recenti come NInject e Moq.

Ad esempio, diciamo che voglio registrare un metodo con un'API e che l'API deve ottenere il nome del metodo

Data questa classe:

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

Prima, era molto comune vedere gli sviluppatori fare questo con stringhe e tipi (o qualcos'altro in gran parte basato su stringhe):

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

Bene, questo fa schifo a causa della mancanza di una digitazione forte. E se rinominassi "SomeMethod"? Ora, in 3.5, tuttavia, posso farlo in modo fortemente tipizzato:

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

In cui la classe RegisterMethod utilizza in Expression<Action<T>>questo modo:

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

Questa è una grande ragione per cui sono innamorato di Lambdas e Expression Trees in questo momento.


3
Ho una classe di utilità di riflessione che fa lo stesso con FieldInfo, PropertyInfo, ecc ...
Olmo,

Sì, è grandioso. Sono stato in grado di utilizzare metodi come questo per scrivere codice come EditValue(someEmployee, e => e.FirstName);nella mia logica aziendale e farlo generare automaticamente tutta la logica idraulica per un ViewModel e View per modificare quella proprietà (quindi, un'etichetta con il testo "First Name" e un TextBox con un'associazione che chiama il setter della proprietà FirstName quando l'utente modifica il nome e aggiorna la vista utilizzando il getter). Questa sembra essere la base per la maggior parte dei nuovi DSL interni in C #.
Scott Whitlock,

4
Penso che questi non siano tanto meno conosciuti quanto meno compresi.
Justin Morgan,

Perché è necessario registrare un metodo? Non l'ho mai usato prima: dove e quando sarebbe usato?
MoonKnight,

209

la " resa " mi sarebbe venuta in mente. Alcuni degli attributi come [DefaultValue ()] sono anche tra i miei preferiti.

La parola chiave " var " è un po 'più nota, ma è possibile utilizzarla anche nelle applicazioni .NET 2.0 (purché si usi il compilatore .NET 3.5 e lo imposti sul codice di output 2.0) non sembra essere molto conosciuta bene.

Modifica: kokos, grazie per aver sottolineato il ?? operatore, è davvero molto utile. Dato che è un po 'difficile cercarlo su Google (dato che ?? è appena ignorato), ecco la pagina di documentazione MSDN per quell'operatore: ?? Operatore (riferimento C #)


14
La documentazione del valore predefinito dice che non sta realmente impostando il valore della proprietà. È solo un aiuto per visualizzatori e generatori di codice.
Boris Callens,

2
Come per DefaultValue: nel frattempo alcune librerie lo usano. ASP.net MVC utilizza DefaultValue sui parametri di un'azione del controller (che è molto utile per i tipi non annullabili). A rigor di termini ovviamente, questo è un generatore di codice in quanto il valore non è impostato dal compilatore ma dal codice MVC.
Michael Stum

6
Il nome per ?? operatore è l'operatore "Null Coalescing"
Armstrongest

la resa è la mia preferita, l'operatore di coalizione è comunque lì. Non vedo nulla sulla CAS, sulla firma dell'assembly, sui nomi forti, sul GAC ... Suppongo che solo CAS sia C # ... ma così tanti sviluppatori non hanno idea della sicurezza.
BrainSlugs83,

198

Tendo a scoprire che la maggior parte degli sviluppatori C # non conosce tipi "nullable". Fondamentalmente, primitive che possono avere un valore nullo.

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

Impostare un doppio nullable, num1 , su null, quindi impostare un doppio normale, num2 , su num1 o -100 se num1 era null.

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

un'altra cosa sul tipo Nullable:

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

è return String.Empty. Controlla questo link per maggiori dettagli


1
DateTime non può essere impostato su null.
Jason Jackson,

2
Quindi "int" è solo zucchero sintattico C # per System.Int32? In realtà esiste un supporto compilatore costruito attorno ai tipi Nullable, che consente di impostarli su null, ad esempio (che non può essere fatto usando solo le strutture generiche) e di inscatolarli come tipo sottostante.
P Daddy,

4
@P Daddy - sì, int è lo zucchero sintattico per System.Int32. Sono completamente intercambiabili, proprio come int? === Int32? === Nullable <Int32> === Nullable <int>
cjk

6
@ck: Sì, int è un alias per System.Int32, come T? è un alias per Nullable <T>, ma non è solo zucchero sintattico. È una parte definita della lingua. Gli alias non solo facilitano la lettura del codice, ma si adattano meglio al nostro modello. Esprimere Nullable <Doppio> come doppio? sottolinea la prospettiva che il valore così contenuto sia (o potrebbe essere) una doppia, non solo una struttura generica istanziata sul tipo Double. (continua)
P Daddy,

3
... In ogni caso, l'argomento non riguardava gli alias (che era solo una cattiva analogia, suppongo), ma che i tipi nullable - usando qualunque sintassi che preferisci - sono davvero una caratteristica del linguaggio, non solo un prodotto di generici. Non è possibile riprodurre tutte le funzionalità di nullable (confronto / assegnazione di null, inoltro operatore, boxe di tipo sottostante o null, compatibilità con coalescenza nulla e asoperatori) con i soli generici. Nullable <T> da solo è rudimentale e tutt'altro che stellare, ma il concetto di tipi nullable come parte del linguaggio è kick ass.
P Daddy,

193

Ecco alcune interessanti funzionalità C # nascoste, sotto forma di parole chiave C # non documentate:

__makeref

__reftype

__refvalue

__arglist

Queste sono parole chiave C # non documentate (anche Visual Studio le riconosce!) A cui sono state aggiunte per un boxing / unboxing più efficiente prima dei farmaci generici. Lavorano in coordinamento con la struttura System.TypedReference.

C'è anche __arglist, che viene utilizzato per elenchi di parametri di lunghezza variabile.

Una cosa di cui la gente non sa molto è System.WeakReference - una classe molto utile che tiene traccia di un oggetto ma consente comunque al garbage collector di raccoglierlo.

La funzione "nascosta" più utile sarebbe la parola chiave return return. Non è davvero nascosto, ma molte persone non lo sanno. LINQ è costruito sopra questo; consente di eseguire query ritardate generando una macchina a stati sotto il cofano. Raymond Chen ha recentemente pubblicato dei dettagli interni e grintosi .


2
Maggiori dettagli sulle parole chiave non documentate di Peter Bromberg . Ancora non capisco se ci sono ragioni per usarli mai.
HuBeZa,

@HuBeZa con l'avvento dei generici, non ci sono molte (nessuna?) Buone ragioni per usare __refType, __makeref e __refvalue. Questi erano usati principalmente per evitare la boxe prima dei generici in .NET 2.
Judah Gabriel Himango

Matt, con l'introduzione dei generici in .NET 2, ci sono pochi motivi per usare queste parole chiave, poiché il loro scopo era quello di evitare il pugilato quando si tratta di tipi di valore. Vedi il link di HuBeZa e vedi anche codeproject.com/Articles/38695/UnCommon-C-keywords-A-Look#ud
Judah Gabriel Himango

185

Unions (il tipo di memoria condivisa C ++) in C # puro e sicuro

Senza ricorrere a modalità e puntatori non sicuri, è possibile fare in modo che i membri della classe condividano lo spazio di memoria in una classe / struttura. Data la seguente classe:

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

È possibile modificare i valori dei campi byte modificando il campo Int32 e viceversa. Ad esempio, questo programma:

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

Emette questo:

2147483647
FF FF FF 7F
65535

basta aggiungere usando System.Runtime.InteropServices;


7
@George, fa miracoli quando comunichi con app legacy tramite socket usando dichiarazioni di unione c.
scottm,

2
C'è anche significato dire int e float all'offset 0. È quello che ti serve se vuoi manipolare i numeri in virgola mobile come maschere di bit, cosa che a volte vuoi. Soprattutto se vuoi imparare nuove cose sui numeri in virgola mobile.
John Leidegren,

2
La cosa fastidiosa di questo è che se hai intenzione di usare questa è una struttura che il compilatore ti costringerà a impostare TUTTE le variabili nella funzione init. Quindi se hai: public A (int int32) {Int32 = int32; } genererà "Il campo 'Uno' deve essere completamente assegnato prima che il controllo venga restituito al chiamante", quindi devi impostare Uno = Due = Tre = Quattro = 0; anche.
Manixrock,

2
Questo ha i suoi usi, principalmente con dati binari. Uso una struttura "Pixel" con int32 @ 0 e quattro byte per i quattro componenti @ 0, 1, 2 e 3. Ottimo per manipolare i dati delle immagini in modo rapido e semplice.
ringhio

57
Avvertenza: questo approccio non tiene conto dell'endianità. Ciò significa che il tuo codice C # non funzionerà allo stesso modo su tutte le macchine. Sulle CPU little-endian (che memorizzano prima il byte meno significativo), verrà utilizzato il comportamento mostrato. Ma su CPU big-endian, i byte usciranno invertiti da quello che ti aspettavi. Fai attenzione a come lo usi nel codice di produzione: il tuo codice potrebbe non essere portatile per determinati dispositivi mobili e altri hardware e potrebbe rompersi in modi non ovvi (ad esempio due file apparentemente nello stesso formato ma in realtà con ordine di byte invertito).
Ray Burns,

176

Utilizzo di @ per nomi di variabili che sono parole chiave.

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

38
Perché dovresti usare una parola chiave come nome variabile? Mi sembra che ciò renderebbe il codice meno leggibile e offuscato.
Jon,

41
Bene, la ragione per cui è lì è che la CLI lo richiede per l'interoperabilità con altre lingue che potrebbero usare parole chiave C # come nomi dei membri
Mark Cidade,

69
Se hai mai voluto usare gli helper HTML di asp.net MVC e definire una classe HTML, sarai felice di sapere che puoi usare @class in modo che non venga riconosciuto come parola chiave della classe
Boris Callens,

31
Ottimo per i metodi di estensione. pubblico statico vuoto DoSomething (questo Bar @this, string foo) {...}
Jonathan C Dickinson,

45
@zihotki: Wrong. var a = 5; Console.WriteLine (@a); Stampe 5
SLaks

168

Se si desidera uscire dal programma senza richiamare finalmente blocchi o finalizzatori, utilizzare FailFast :

Environment.FailFast()

12
Si noti che questo metodo crea anche un dump della memoria e scrive un messaggio nel registro errori di Windows.
RickNZ,

1
Va notato che non verranno chiamati finalizzatori o eventi di
scaricamento del

1
+1 per il suggerimento, ma questo non è C #, è BCL di .NET.
Abele

System.Diagnostics.Process.GetCurrentProcess (). Kill () è più veloce
Tolgahan Albayrak,

153

Restituzione di tipi anonimi da un metodo e accesso ai membri senza riflessione.

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

42
Questo non ti dà davvero niente. In realtà è pericoloso. Cosa succede se GetUserTuple viene modificato per restituire più tipi? Il cast fallirà in fase di esecuzione. Una delle grandi cose di C # /. Net è il controllo del tempo di compilazione. Sarebbe molto meglio creare un nuovo tipo.
Jason Jackson,

9
@Jason Ho detto che probabilmente non è utile ma è sorprendente (e pensavo nascosto).
denis phillips,

31
Anche se fico, questa sembra una scelta di design piuttosto scadente. In pratica hai definito il tipo anonimo in due punti. A quel punto, basta dichiarare una vera struttura e usarla direttamente.
Paul Alexander,

6
@Gorge: una simile convenzione si chiamerebbe ... struct?
R. Martinho Fernandes,

2
questo trucco è denominato "cast per campione" e non funzionerà se il metodo che restituisce un tipo anonimo si trova in un altro assembly.
desco,

146

Eccone uno utile per espressioni regolari e percorsi di file:

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

@ Indica al compilatore di ignorare tutti i caratteri di escape in una stringa.


27
Inoltre, una costante @ accetta newline all'interno. Perfetto quando si assegna uno script multilinea a una stringa.
Tor Haugen,

11
Non dimenticare anche di sfuggire alle virgolette semplicemente raddoppiandole, in altre parole. [code] var candy = @ "I like" "red" "candy canes."; [/ code]
Dave,

5
Tendo a costruire percorsi con Path.Combine. Sicuramente uso @ per regex!
Dan McClain,

6
@new è anche una variabile anziché una parola chiave: @this, @int, @return, @interface ... so on :)
IAbstract

Questo non si avvicina da nessuna parte: ma quali sono le funzionalità o i trucchi più nascosti di C # che persino i fan di C #, i tossicodipendenti e gli esperti conoscono a malapena?
publicgk

141

Mixins. Fondamentalmente, se si desidera aggiungere una funzione a più classi, ma non è possibile utilizzare una classe di base per tutte, fare in modo che ciascuna classe implementi un'interfaccia (senza membri). Quindi, scrivere un metodo di estensione per l'interfaccia , ad es

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

Certo, viene sacrificata una certa chiarezza. Ma funziona!


4
Sì, penso che questo sia il vero potere dei metodi di estensione. Fondamentalmente consentono implementazioni di metodi di interfaccia.
John Bubriski

Questo è utile anche se stai usando NHibernate (o Castle ActiveRecord) e devi usare le interfacce per le tue collezioni. In questo modo è possibile dare un comportamento alle interfacce di raccolta.
Ryan Lundy,

Questo è fondamentalmente il modo in cui tutti i metodi LINQ sono implementati, per la cronaca.
WCWedin

Ecco un link che parla di ciò che ho menzionato sopra, usando i metodi di estensione con interfacce di raccolta in NHibernate o Castle ActiveRecord: devlicio.us/blogs/billy_mccafferty/archive/2008/09/03/…
Ryan Lundy

7
Se solo avessero permesso le proprietà dell'estensione !!!! Odiavo dover scrivere un metodo di estensione che supplicava di essere una proprietà di sola lettura ....
John Gibb,

130

Non so perché qualcuno vorrebbe mai usare Nullable <bool> però. :-)

Vero, falso, FileNotFound ?


87
se si aspetta che un utente risponda a una domanda sì no, allora nulla sarebbe appropriato se la domanda non ha avuto risposta
Omar Kooheji

22
I tipi nullable sono utili per l'interazione con un database in cui le colonne della tabella sono spesso nullable.
tuinstoel

11
Sì, no, Maybee?
Dan Blair,

21
Memorizza i valori di un CheckBox ThreeState
Shimmy Weitzhandler il

8
Come in SQL: Sì / no / sconosciuto.
erikkallen,

116

Questo non è "nascosto" tanto quanto è erroneamente chiamato.

Molta attenzione è riservata agli algoritmi "map", "ridurre" e "filtro". Ciò che la maggior parte delle persone non capisce è che .NET 3.5 ha aggiunto tutti e tre questi algoritmi, ma ha dato loro nomi molto SQL-ish, in base al fatto che fanno parte di LINQ.

"map" => Seleziona
Trasforma i dati da un modulo a un altro

"ridurre" =>
Aggrega i valori aggregati in un unico risultato

"filter" => Dove filtra i
dati in base a un criterio

La capacità di utilizzare LINQ per eseguire lavori in linea su raccolte utilizzate in passato per iterazioni e condizionali può essere incredibilmente preziosa. Vale la pena imparare come tutti i metodi di estensione LINQ possono aiutare a rendere il codice molto più compatto e gestibile.


1
Select agisce anche come la funzione "return" nelle monadi. Vedi stackoverflow.com/questions/9033/hidden-features-of-c#405088
Mark Cidade

1
L'uso di "select" è necessario solo se si utilizza la sintassi SQLish. Se si utilizza la sintassi del metodo di estensione - someCollection.Where (item => item.Price> 5.99M) - non è richiesto l'uso di istruzioni select.
Brad Wilson

7
@Brad, quella (dove) è un'operazione di filtro. Prova a eseguire un'operazione su una mappa senza selezionare ...
Eloff,

2
LINQ è la cosa più importante che è successo a C #, a mio parere: stackoverflow.com/questions/2398818/...
Leniel Maccaferri

1
La firma più piccola di Aggregate è la funzione "riduci", la firma centrale di Aggregate è la funzione "piega" molto più potente!
Brett Widmeier,

115
Environment.NewLine

per newline indipendenti dal sistema.


10
La cosa fastidiosa di questo, è che non è incluso nel framework compatto.
Stormenet,

14
Vale la pena sottolineare che questo è specifico per la piattaforma host dell'applicazione, quindi se si stanno creando dati destinati a un altro sistema, è necessario utilizzare \ n o \ r \ n in modo appropriato.
Maglia

Questo fa parte del BCL di .NET, non una funzionalità di C # in sé.
Abel

111

Se stai cercando di usare parentesi graffe all'interno di un'espressione 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"

19
@Kyralessa: In realtà, sì, sono parentesi graffe, ma "parentesi graffe" è un nome alternativo per loro. [e ]sono parentesi quadre e <e >sono parentesi angolari. Vedi en.wikipedia.org/wiki/Bracket .
icktoofay,

4
Hai ragione. Ma quando ho commentato, non ho detto parentesi "ricci".
Ryan Lundy,

2
Molto bello da sottolineare. Ricorda che il mio primo String.Format sembrava: String.Format ("{0} Sono tra parentesi graffe {1} {2} {3}", "{", "}", 3, "mouse ciechi"); Una volta ho scoperto che fuggire questi è stato fatto usando {{and}} ero così felice :)
Gertjan,

Muahahahaa ... Programmando già 3 anni in .Net e non lo sapevo. : D
Arnis Lapsa,

parentesi "ricci" che agiscono in modo simile alle sequenze di escape ??
Pratik,

104
  1. ?? - operatore a coalescenza
  2. using ( istruzione / direttiva ) - ottima parola chiave che può essere utilizzata per più di una semplice chiamata a Dispose
  3. di sola lettura - dovrebbe essere usato di più
  4. netmodules - peccato che non ci sia supporto in Visual Studio

6
using può anche essere usato per aliasare uno spazio dei nomi lungo in una stringa più conveniente, ovvero: using ZipEncode = MyCompany.UtilityCode.Compression.Zip.Encoding; C'è di più qui: msdn.microsoft.com/en-us/library/sf0df423.aspx
Dave R.

2
Non è davvero la stessa cosa. Quando si chiama Dispose, è possibile utilizzare l'istruzione using, quando si aliasano i tipi che si sta utilizzando una direttiva using.
Øyvind Skaar,

2
Nel caso in cui desideri un nome al numero 1 (come hai fatto con l'operatore ternario), ?? viene chiamato l'operatore null coalescente.
J. Steen,

4
@LucasAardvark: come ha detto J Steen, si chiama operatore a coalescenza nulla. Cerca quello!
Kokos,

1
Cercare ?? operatore su google prova: google.com/search?q=c%23+%3F%3F+operator
backslash17

103

@Ed, sono un po 'reticente nel pubblicare questo in quanto è poco più di un pignolo. Tuttavia, vorrei sottolineare che nel tuo esempio di codice:

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

Se hai intenzione di usare 'is', perché seguirlo con un cast sicuro usando 'as'? Se hai accertato che obj è davvero MyClass, un cast standard:

c = (MyClass)obj

... non fallirà mai.

Allo stesso modo, potresti semplicemente dire:

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

Non ne so abbastanza delle viscere di .NET per essere sicuro, ma il mio istinto mi dice che ciò ridurrebbe al massimo due operazioni di cast di tipo fino a un massimo di una. È improbabile che rompa la banca di elaborazione in entrambi i casi; personalmente, penso che anche quest'ultima forma sia più pulita.


16
Se il cast è del tipo esatto (cast su "A" quando l'oggetto è "A", non derivato da esso), il cast dritto è ~ 3 volte più veloce di "as". Quando si lancia un tipo derivato (cast su "A" quando l'oggetto è "B", che deriva da "A"), il cast rettilineo è ~ 0,1x più lento di "as". "è", quindi "come" è semplicemente stupido.
P Daddy,

2
No, ma potresti scrivere "if ((c = obj come MyClass)! = Null)".
Dave Van den Eynde,

10
ise asnon eseguirà il cast dell'utente. Pertanto, il codice sopra riportato chiede isall'operatore se obj è derivato da MyClass (o ha un cast implicito definito dal sistema). Inoltre, isnon riesce null. Entrambi questi casi limite possono essere importanti per il tuo codice. Ad esempio, potresti voler scrivere: if( obj == null || obj is MyClass ) c = (MyClass)obj; Ma questo è strettamente diverso da: try { c = (MyClass)obj; } catch { }poiché il primo non eseguirà conversioni definite dall'utente, ma il secondo lo farà. Senza il nullcontrollo, anche il primo non verrà impostato cquando lo objè null.
Adam Luter,

2
In IL, un cast va a CASTCLASS ma un as / is va a un'istruzione ISINST.
John Gibb,

5
Ho eseguito un test per questo, colata IEnumerable<int>a List<int>, e la colata object( new object()) a IEnumerable<int>, per assicurarsi che non vi siano errori: getto diretto: 5.43ns, è-> come del cast: 6.75ns, come Cast: 5.69ns. Quindi test di cast non validi: cast diretto: 3125000ns, come cast: 5.41ns. Conclusione: smetti di preoccuparti del fattore 1% e assicurati di usare è / come quando il cast potrebbe non essere valido, poiché le eccezioni (anche se gestite) sono MOLTO lente rispetto al cast, stiamo parlando di un fattore 578000 più lento. Ricorda che l'ultima parte, il resto non ha importanza (.Net FW 4.0, build di rilascio)
Aidiakapi,

98

Forse non è una tecnica avanzata, ma una che vedo tutto il tempo che mi fa impazzire:

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

può essere condensato in:

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

10
L'operatore ternario è stato bandito dal mio gruppo. Ad alcune persone non piace, anche se non ho mai capito il perché.
Justin R.,

13
Immagino perché non sono le stesse cose, essere un operatore non una dichiarazione. Preferisco il primo approccio da solo. È più coerente e facilmente espandibile. Gli operatori non possono contenere istruzioni, quindi nel momento in cui devi espandere il corpo, dovrai convertire
quell'operatore

16
può essere condensato in x ++; Ok è inutile ^^
François

5
@Guillaume: per tenere conto di tutti i valori di x: x = 2 + System.Math.Min (1, System.Math.Abs ​​(x-1));
mbeckish,

38
In realtà si chiama "operatore condizionale" - è un operatore ternario perché accetta tre argomenti. en.wikipedia.org/wiki/Conditional_operator
Blorgbeard esce il
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.