c# - html agility pack remove tags




Caratteristiche nascoste di C#? (20)

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

where T : struct

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

Alcuni di noi hanno anche imparato cose come Generics , tipi anonimi , lambdas , LINQ , ...

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

Ecco le caratteristiche rivelate finora:


parole

attributi

Sintassi

Caratteristiche del linguaggio

Funzionalità di Visual Studio

Struttura

Metodi e proprietà

Consigli e trucchi

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

Altro


Da CLR via C # :

Durante la normalizzazione delle stringhe, si consiglia vivamente di utilizzare ToUpperInvariant anziché ToLowerInvariant poiché Microsoft ha ottimizzato il codice per l'esecuzione di confronti maiuscoli .

Ricordo che una volta il mio collega ha sempre modificato le stringhe in maiuscolo prima di confrontarle. Mi sono sempre chiesto perché lo fa perché ritengo sia più "naturale" convertire prima in lettere minuscole. Dopo aver letto il libro ora so perché.


La @ dice al compilatore di ignorare qualsiasi carattere di escape in una stringa.

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

Se hai

string s = @"cat
             dog
             fish"

in realtà verrà stampato come (notare che include anche gli spazi bianchi usati per il rientro):

cat
             dog
             fish

  1. ?? - operatore coalescente
  2. usando ( statement / directive ) - ottima parola chiave che può essere usata per qualcosa di più della semplice chiamata Dispose
  3. readonly - dovrebbe essere usato di più
  4. netmodules - peccato che non ci sia supporto in Visual Studio

Attributi in generale, ma soprattutto DebuggerDisplay . Ti risparmia anni.


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 gli inizializzatori dell'oggetto:

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

diventa

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

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

__makeref

__reftype

__refvalue

__arglist

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

C'è anche __arglist, che viene usato per liste di parametri a 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 pubblicato di recente sui dettagli interni e grintosi .


Il mio trucco preferito è usare l' operatore di coalesce nullo e le parentesi per creare istanze automagicamente per me.

private IList<Foo> _foo;

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

La parola chiave "predefinita" nei tipi generici:

T t = default(T);

restituisce un 'null' se T è un tipo di riferimento, e 0 se è un int, false se è un booleano, eccetera.


Penso che una delle caratteristiche meno apprezzate e meno conosciute di C # (.NET 3.5) siano Expression Trees , specialmente se combinate con Generics e Lambdas. Questo è un approccio alla creazione delle API che utilizzano le nuove librerie come NInject e Moq.

Ad esempio, supponiamo che io voglia registrare un metodo con un'API e che l'API abbia bisogno di ottenere il nome del metodo

Data questa classe:

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

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

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

Beh, questo fa schifo a causa della mancanza di caratteri forti. Cosa succede se rinominare "SomeMethod"? Ora, in 3.5, tuttavia, posso farlo in modo fortemente tipizzato:

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

In cui la classe RegisterMethod utilizza 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.


Questo non è C # di per sé, ma non ho visto nessuno che usi veramente 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;

Tendo a scoprire che molti sviluppatori C # non conoscono i tipi 'nullable'. Fondamentalmente, le primitive che possono avere un valore nullo.

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

Imposta un double nullable, num1 , su null, quindi imposta un double regolare, num2 , su num1 o -100 se num1 era nullo.

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

un'altra cosa sul tipo di Nullable:

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

è di ritorno String.Empty. Controlla this link per maggiori dettagli


Tutto il resto, in più

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 diversi ambiti:

public int MyId { get; private set; }

Grazie a @pzycoman per avermi ricordato:

5) Alias ​​dello spazio dei nomi (non è probabile che tu abbia 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();

la " yield " mi sarebbe venuta in mente. Alcuni degli attributi come DefaultValueAttribute sono anche tra i miei preferiti.

La parola chiave " var " è un po 'più conosciuta, ma è possibile utilizzarla anche nelle applicazioni .NET 2.0 (se si usa il compilatore .NET 3.5 e si imposta sul codice di output 2.0) non sembra essere molto conosciuto bene.

Modifica: kokos, grazie per aver sottolineato il ?? operatore, è davvero molto utile. Dato che è un po 'difficile da google (perché è appena ignorato), ecco la pagina di documentazione di MSDN per quell'operatore: ?? ??


Evitare il controllo di gestori di eventi nulli

Aggiungere un delegato vuoto agli eventi alla 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!

Lascia fare a te

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

Invece di questo

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

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


lambda e tipo inferenza 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 un new CancellationEventHandler né devo specificare i tipi di sender ed e , sono deducibili dall'evento. Questo è il motivo per cui è meno complicato scrivere l'intero delegate (blah blah) che richiede anche di specificare i tipi di parametri.

Lambda non ha bisogno di restituire nulla e il tipo di inferenza è estremamente potente in un contesto come questo.

E a proposito, puoi sempre restituire Lambdas che rende Lambdas nel senso di 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) =>

Ecco perché sono felice di aver preso la classe di programmazione funzionale :-)

Oltre ai puntatori in C, penso che sia l'altra cosa fondamentale che dovresti imparare :-)


Ecco uno utile per le espressioni regolari e i percorsi dei file:

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

La @ dice al compilatore di ignorare qualsiasi carattere di escape in una stringa.


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

Viene prestata molta attenzione agli algoritmi "map", "reduce" e "filter". Quello che molte persone non si rendono conto è che .NET 3.5 ha aggiunto tutti e tre questi algoritmi, ma ha dato loro dei nomi SQL-ish, basati sul fatto che fanno parte di LINQ.

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

"reduce" =>
Aggrega i valori degli aggregati in un unico risultato

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

La possibilità di utilizzare LINQ per eseguire il lavoro in linea su raccolte che utilizzavano iterazioni e condizionali può essere estremamente utile. Vale la pena imparare come tutti i metodi di estensione LINQ possono aiutare a rendere il codice molto più compatto e manutenibile.


Restituzione di tipi anonimi da un metodo e accesso ai membri senza alcuna 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;
}

@Ed, sono un po 'reticente a postare questo dato che è poco più che fare il pignolo. Tuttavia, vorrei sottolineare che nel tuo esempio di codice:

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

Se stai per usare "è", perché seguirlo con un cast sicuro usando "come"? Se hai accertato che obj è effettivamente MyClass, un cast standard di bog:

c = (MyClass)obj

... non fallirà mai.

Allo stesso modo, potresti solo dire:

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

Non ne so abbastanza delle interiora di .NET per essere sicuro, ma il mio istinto mi dice che questo ridurrebbe un massimo di due operazioni di tipo cast fino ad un massimo di uno. È difficilmente possibile rompere la banca di elaborazione in entrambi i casi; personalmente, penso che anche quest'ultima forma sia più pulita.


Mixins. In sostanza, se si desidera aggiungere una funzione a più classi, ma non è possibile utilizzare una classe base per tutte, assegnare a ciascuna classe l'implementazione di un'interfaccia (senza membri). Quindi, scrivi un metodo di estensione per l'interfaccia , es

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

Certo, una certa chiarezza viene sacrificata. Ma funziona!





hidden-features