tutorial - langage c# pdf




Caractéristiques cachées de C#? (20)

De CLR via C # :

Lors de la normalisation des chaînes, il est fortement recommandé d'utiliser ToUpperInvariant au lieu de ToLowerInvariant, car Microsoft a optimisé le code pour effectuer des comparaisons majuscules .

Je me souviens d'une fois mon collègue a toujours changé les chaînes en majuscules avant de comparer. Je me suis toujours demandé pourquoi il le fait parce que je pense qu'il est plus «naturel» de convertir en minuscules en premier. Après avoir lu le livre maintenant je sais pourquoi.

Cela m'est venu à l'esprit après avoir appris ce qui suit de cette question :

where T : struct

Nous, développeurs C #, connaissons tous les bases de C #. Je veux dire les déclarations, conditions, boucles, opérateurs, etc.

Certains d'entre nous ont même maîtrisé les choses comme les Generics , les types anonymes , lambdas , LINQ , ...

Mais quelles sont les caractéristiques les plus cachées ou les astuces de C # que même les fans de C #, les toxicomanes, les experts connaissent à peine?

Voici les caractéristiques révélées jusqu'à présent:


Mots clés

Les attributs

Syntaxe

Caractéristiques linguistiques

Fonctionnalités Visual Studio

Cadre

Méthodes et propriétés

Conseils & Astuces

  • Bonne méthode pour les gestionnaires d'événements par Andreas HR Nilsson
  • Comparaisons majuscules par John
  • Accéder aux types anonymes sans réflexion par dp
  • Un moyen rapide d'instancier par la paresse les propriétés de collection par Will
  • JavaScript inline-inline-fonctions de roosteronacid

Autre


Le @ indique au compilateur d'ignorer les caractères d'échappement dans une chaîne.

Je voulais juste clarifier celui-ci ... il ne lui dit pas d'ignorer les caractères d'échappement, il dit en fait au compilateur d'interpréter la chaîne comme un littéral.

Si tu as

string s = @"cat
             dog
             fish"

il imprimera réellement en tant que (notez qu'il inclut même l'espace utilisé pour l'indentation):

cat
             dog
             fish

  1. ?? - coalescing operator
  2. using ( statement / directive ) - great keyword that can be used for more than just calling Dispose
  3. readonly - should be used more
  4. netmodules - too bad there's no support in Visual Studio

" yield " me viendrait à l'esprit. Certains des attributs comme DefaultValueAttribute sont également parmi mes favoris.

Le mot-clé " var " est un peu plus connu, mais que vous pouvez aussi utiliser dans les applications .NET 2.0 (aussi longtemps que vous utilisez le compilateur .NET 3.5 et le mettre en sortie du code 2.0) ne semble pas très connu bien.

Edit: kokos, merci de souligner le ?? opérateur, c'est vraiment très utile. Comme il est un peu difficile de google pour cela (comme est juste ignoré), voici la page de documentation MSDN pour cet opérateur: ?? ??


Ce n'est pas le C # en soi, mais je n'ai vu personne qui utilise réellement System.IO.Path.Combine() dans la mesure où ils le devraient. En fait, toute la classe Path est vraiment utile, mais personne ne l'utilise!

Je suis prêt à parier que chaque application de production a le code suivant, même si ce n'est pas le cas:

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

De Rick Strahl :

Vous pouvez enchaîner le ?? opérateur afin que vous puissiez faire un tas de comparaisons nulles.

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

Génériques avec alias:

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

Il vous permet d'utiliser ASimpleName , au lieu de Dictionary<string, Dictionary<string, List<string>>> .

Utilisez-le lorsque vous utiliserez la même chose générique dans de nombreux endroits.


J'ai tendance à trouver que la plupart des développeurs C # ne connaissent pas les types 'nullable'. Fondamentalement, les primitives qui peuvent avoir une valeur nulle.

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

Définissez un double nullable , num1 , à null, puis définissez un double normal, num2 , à num1 ou -100 si num1 était null.

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

une chose de plus sur le type Nullable:

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

c'est return String.Empty. Consultez this lien pour plus de détails


Je pense que l'une des fonctionnalités les moins appréciées et les moins connues de C # (.NET 3.5) sont les arbres d'expression , en particulier lorsqu'ils sont combinés avec Generics et Lambdas. C'est une approche de la création d'API que les bibliothèques plus récentes comme NInject et Moq utilisent.

Par exemple, disons que je veux enregistrer une méthode avec une API et que cette API doit obtenir le nom de la méthode

Compte tenu de cette classe:

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

Avant, il était très fréquent de voir les développeurs faire cela avec des chaînes et des types (ou quelque chose d'autre largement basés sur des chaînes de caractères):

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

Eh bien, ça craint à cause du manque de typage fort. Que faire si je renommer "SomeMethod"? Maintenant, en 3.5 cependant, je peux le faire d'une manière fortement typée:

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

Dans lequel la classe RegisterMethod utilise Expression<Action<T>> comme ceci:

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

C'est une grande raison pour laquelle je suis amoureux des Lambdas et des Expression Trees en ce moment.


Le mot-clé 'default' dans les types génériques:

T t = default(T);

donne un 'nul' si T est un type de référence, et 0 s'il s'agit d'un int, false s'il s'agit d'un booléen, etc.


Si vous voulez quitter votre programme sans appeler de FailFast ou de finaliseurs, utilisez FailFast :

Environment.FailFast()

Tout le reste, plus

1) génériques implicites (pourquoi seulement sur les méthodes et pas sur les classes?)

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

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

2) lambdas simples avec un paramètre:

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

3) types et initiateurs anonymes:

//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 autre:

4) Les propriétés automatiques peuvent avoir des étendues différentes:

public int MyId { get; private set; }

Merci @pzycoman pour me rappeler:

5) Alias ​​d'espace de noms (pas que vous ayez besoin de cette distinction particulière):

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

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

Voici quelques fonctionnalités C # cachées intéressantes, sous la forme de mots-clés C # non documentés:

__makeref

__reftype

__refvalue

__arglist

Ce sont des mots-clés C # non documentés (même Visual Studio les reconnaît!) Qui ont été ajoutés pour un boxing / unboxing plus efficace avant les génériques. Ils travaillent en coordination avec la structure System.TypedReference.

Il y a aussi __arglist, qui est utilisé pour les listes de paramètres de longueur variable.

System.WeakReference est une classe très utile qui garde la trace d'un objet tout en permettant au garbage collector de le collecter.

La fonctionnalité "cachée" la plus utile serait le mot clé de rendement. Ce n'est pas vraiment caché, mais beaucoup de gens ne le savent pas. LINQ est construit au-dessus de cela; il permet des requêtes exécutées par retard en générant une machine d'état sous le capot. Raymond Chen a récemment publié sur les détails internes, graveleux .


Évitez de rechercher des gestionnaires d'événements null

L'ajout d'un délégué vide aux événements lors de la déclaration, supprimant le besoin de toujours vérifier l'événement pour null avant de l'appeler est génial. Exemple:

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

Laissez-vous faire ça

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

Au lieu de cela

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

S'il vous plaît également voir cette discussion connexe et ce blog par Eric Lippert sur ce sujet (et les inconvénients possibles).


lambdas et l'inférence de type sont sous-estimés. Lambdas peut avoir plusieurs instructions et elles se doublent automatiquement en tant qu'objet délégué compatible (assurez-vous simplement que la signature correspond) comme dans:

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

Notez que je n'ai pas de new CancellationEventHandler et que je n'ai pas besoin de spécifier les types d' sender et e , ils sont déductibles de l'événement. C'est pourquoi il est moins encombrant d'écrire le delegate (blah blah) entier delegate (blah blah) qui vous demande également de spécifier les types de paramètres.

Les Lambdas n'ont pas besoin de retourner quoi que ce soit et l'inférence de type est extrêmement puissante dans un contexte comme celui-ci.

Et BTW, vous pouvez toujours retourner Lambdas qui font Lambdas dans le sens de la programmation fonctionnelle. Par exemple, voici un lambda qui fait un lambda qui gère un événement 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);

Notez le chaînage: (dx, dy) => (sender, e) =>

Voilà pourquoi je suis heureux d'avoir pris la classe de programmation fonctionnelle :-)

Autre que les pointeurs en C, je pense que c'est l'autre chose fondamentale que vous devriez apprendre :-)


@Ed, I'm a bit reticent about posting this as it's little more than nitpicking. However, I would point out that in your code sample:

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

If you're going to use 'is', why follow it up with a safe cast using 'as'? If you've ascertained that obj is indeed MyClass, a bog-standard cast:

c = (MyClass)obj

...is never going to fail.

Similarly, you could just say:

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

I don't know enough about .NET's innards to be sure, but my instincts tell me that this would cut a maximum of two type casts operations down to a maximum of one. It's hardly likely to break the processing bank either way; personally, I think the latter form looks cleaner too.


If you're trying to use curly brackets inside a String.Format expression...

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"

Maybe not an advanced technique, but one I see all the time that drives me crazy:

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

can be condensed to:

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

Returning anonymous types from a method and accessing members without reflection.

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

This one is not "hidden" so much as it is misnamed.

A lot of attention is paid to the algorithms "map", "reduce", and "filter". What most people don't realize is that .NET 3.5 added all three of these algorithms, but it gave them very SQL-ish names, based on the fact that they're part of LINQ.

"map" => Select
Transforms data from one form into another

"reduce" => Aggregate
Aggregates values into a single result

"filter" => Where
Filters data based on a criteria

The ability to use LINQ to do inline work on collections that used to take iteration and conditionals can be incredibly valuable. It's worth learning how all the LINQ extension methods can help make your code much more compact and maintainable.





hidden-features