Caractéristiques cachées de C #? [fermé]


1475

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

where T : struct

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

Certains d'entre nous ont même maîtrisé des trucs comme les génériques , les types anonymes , les lambdas , LINQ , ...

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

Voici les fonctionnalités révélées jusqu'à présent:


Mots clés

Les attributs

Syntaxe

  • ??(coalesce nulls ) opérateur par kokos
  • Signalisation numérique par Nick Berardi
  • where T:newpar Lars Mæhlum
  • Génériques implicites par Keith
  • Lambdas à un paramètre par Keith
  • Propriétés automatiques par Keith
  • Alias ​​d'espace de noms par Keith
  • Verbatim string literals with @ by Patrick
  • enumvaleurs par lfoust
  • @variablenames par marxidad
  • eventopérateurs par marxidad
  • Format des parenthèses de chaîne par Portman
  • Modificateurs d'accessibilité des accesseurs de propriété par xanadont
  • Opérateur conditionnel (ternaire) ( ?:) par JasonS
  • checkedet uncheckedopérateurs par Binoj Antony
  • implicit and explicitopérateurs par Flory

Caractéristiques linguistiques

Fonctionnalités de Visual Studio

Cadre

Méthodes et propriétés

  • String.IsNullOrEmpty()méthode par KiwiBastard
  • List.ForEach()méthode par KiwiBastard
  • BeginInvoke(), EndInvoke()méthodes de Will Dean
  • Nullable<T>.HasValueet Nullable<T>.Valuepropriétés de Rismo
  • GetValueOrDefaultméthode par John Sheehan

Conseils & Astuces

  • Belle 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 paresseusement les propriétés d'une collection par Will
  • Fonctions en ligne anonymes de type JavaScript par roosteronacid

Autre

Réponses:


752

Ce n'est pas C # en soi, mais je n'ai vu personne qui utilise vraiment System.IO.Path.Combine()autant qu'il le devrait. En fait, toute la classe Path est vraiment utile, mais personne ne l'utilise!

Je suis prêt à parier que chaque application de production possède le code suivant, même s'il ne devrait pas:

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

584

les 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'en ai pas new CancellationEventHandleret je n'ai pas besoin de spécifier les types de senderet e, ils sont déductibles de l'événement. C'est pourquoi cela est moins fastidieux d'écrire le tout delegate (blah blah)ce qui nécessite également de spécifier des types de paramètres.

Lambdas n'a 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 des Lambdas qui font des Lambdas au sens de la programmation fonctionnelle. Par exemple, voici un lambda qui crée 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 suivi le cours de programmation fonctionnelle :-)

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


528

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;

454

Génériques aliasés:

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 longue et complexe dans de nombreux endroits.


438

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 en majuscules .

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


254
Lorsque vous "convertissez une chaîne en majuscules", vous créez un deuxième objet chaîne temporaire. Je pensais que ce genre de comparaison n'était pas préféré, que la meilleure façon était: String.Equals (stringA, stringB, StringComparison.CurrentCultureIgnoreCase) qui ne crée pas du tout cette chaîne jetable.
Anthony

32
Quel type d'optimisation pouvez-vous effectuer pour comparer des chaînes majuscules qui ne peuvent pas être effectuées sur des chaînes minuscules? Je ne comprends pas pourquoi l'un serait plus optimal que l'autre.
Parappa

36
La conversion en majuscules plutôt qu'en minuscules peut également empêcher un comportement incorrect dans certaines cultures. Par exemple, en turc, deux i minuscules mappent vers le même i majuscule. Google «turc i» pour plus de détails.
Neil

34
J'ai essayé de comparer ToUpperInvariant et ToLowerInvariant. Je ne trouve aucune différence dans leurs performances sous .NET 2.0 ou 3.5. Certainement rien de ce qui justifie "fortement recommandé" d'utiliser l'un sur l'autre.
Rasmus Faber

19
ToUpperInvariant est préféré car il rend tous les caractères aller-retour. Voir msdn.microsoft.com/en-us/library/bb386042.aspx . Pour des comparaisons, écrivez"a".Equals("A", StringComparison.OrdinalIgnoreCase)
SLaks

408

Mon astuce préférée consiste à utiliser l' opérateur de coalescence nulle et les parenthèses pour instancier automatiquement des collections pour moi.

private IList<Foo> _foo;

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

23
Ne trouvez-vous pas difficile à lire?
Riri

72
C'est un peu difficile à lire pour le no ... er, inexpérimenté. Mais il est compact et contient quelques modèles et fonctionnalités de langage que le programmeur doit connaître et comprendre. Donc, même si c'est difficile au début, cela offre l'avantage d'être une raison d'apprendre.

38
L'instanciation paresseuse est quelque peu abusive car c'est un mauvais choix pour éviter de penser aux invariants de classe. Il a également des problèmes de concurrence.
John Leidegren

17
J'ai toujours été informé que c'était une mauvaise pratique, que d'appeler une propriété ne devrait pas faire quelque chose en tant que tel. Si vous aviez un ensemble là-bas et définissez la valeur sur null, ce serait très étrange pour quelqu'un qui utilise votre API.
Ian

8
@Joel sauf que la définition de ListOfFoo sur null ne fait pas partie du contrat de classe ni n'est une bonne pratique. C'est pourquoi il n'y a pas de passeur. C'est aussi pourquoi ListOfFoo est garanti de retourner une collection et jamais un null. C'est juste une plainte très étrange que si vous faites deux mauvaises choses (faites un setter et définissez une collection sur null), vos attentes seront fausses. Je ne suggérerais pas non plus de faire Environment.Exit () dans le getter. Mais cela n'a rien à voir avec cette réponse.

315

Évitez de rechercher les gestionnaires d'événements nuls

L'ajout d'un délégué vide aux événements lors de la déclaration, supprimant la nécessité 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

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

Au lieu de cela

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

Veuillez également consulter cette discussion connexe et cet article de blog d'Eric Lippert sur ce sujet (et les inconvénients possibles).


87
Je crois qu'un problème apparaîtra si vous comptez sur cette technique et que vous devez ensuite sérialiser la classe. Vous éliminerez l'événement, puis lors de la désérialisation, vous obtiendrez une NullRefference ..... On peut donc simplement s'en tenir à «l'ancienne» façon de faire les choses. C'est plus sûr.
sirrocco

16
vous pouvez toujours définir votre gestionnaire d'événements sur null, vous pouvez donc toujours obtenir une référence null et vous avez toujours une condition de concurrence critique.
Robert Paulson,

64
Un test de profil rapide montre que le gestionnaire d'événements abonné factice sans test nul prend environ 2 fois le temps du gestionnaire d'événements non abonné avec test nul. Le gestionnaire d'événements de multidiffusion sans test nul prend environ 3,5 fois le temps du gestionnaire d'événements à diffusion unique avec test nul.
P Daddy

54
Cela évite la nécessité d'une vérification nulle en ayant toujours un auto-abonné. Même en tant qu'événement vide, cela entraîne des frais généraux dont vous ne voulez pas. S'il n'y a aucun abonné, vous ne voulez pas déclencher l'événement du tout, ne déclenchez pas toujours d'abord un événement factice vide. Je considérerais ce mauvais code.
Keith

56
C'est une terrible suggestion, pour les raisons évoquées ci-dessus. Si vous devez rendre votre code "propre", utilisez une méthode d'extension pour vérifier la valeur null, puis appelez l'événement. Quelqu'un avec des privilèges de modification devrait certainement ajouter les inconvénients à cette réponse.
Greg

305

Tout le reste, plus

1) génériques implicites (pourquoi uniquement sur les méthodes et non 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 anonymes et initialiseurs:

//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 différentes portées:

public int MyId { get; private set; }

Merci @pzycoman de m'avoir rappelé:

5) Alias ​​d'espace de noms (pas que vous ayez probablement 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();

14
dans # 3, vous pouvez faire Enumerable.Range (1,5)
Echostorm

18
je pense que vous avez pu initialiser des tableaux avec int [] nums = {1,2,3}; depuis 1.0 :) n'a même pas besoin du "nouveau" mot
Lucas

13
également lambda sans paramètres () => DoSomething ();
Pablo Retyk

5
J'ai utilisé les deux {get; ensemble interne; } et obtenir; ensemble protégé; }, donc ce modèle est cohérent.
Keith

7
@Kirk Broadhurst - vous avez raison - new web.Control()fonctionnerait également dans cet exemple. La ::syntaxe l'oblige à traiter le préfixe comme un alias d'espace de noms, donc vous pourriez avoir une classe appelée webet la web::Controlsyntaxe fonctionnerait toujours, tandis que la web.Controlsyntaxe ne saurait pas s'il faut vérifier la classe ou l'espace de noms. Pour cette raison, j'ai tendance à toujours utiliser ::lors de la création d'alias d'espace de noms.
Keith

286

Je ne connaissais pas le mot-clé "as" depuis un bon moment.

MyClass myObject = (MyClass) obj;

contre

MyClass myObject = obj as MyClass;

La seconde retournera null si obj n'est pas une MyClass, plutôt que de lever une exception de transtypage de classe.


42
Mais ne le faites pas trop. Beaucoup de gens semblent utiliser as car ils préfèrent la syntaxe même s'ils veulent la sémantique d'un (ToType) x.
Scott Langham

4
Je ne pense pas qu'il offre de meilleures performances. L'avez-vous profilé? (Évidemment, cela se produit lorsque le casting échoue ... mais lorsque vous utilisez le casting (MyClass), les échecs sont exceptionnels .. et extrêmement rares (s'ils se produisent), donc cela ne fait aucune différence.
Scott Langham

7
Ceci n'est plus performant que si le cas habituel est l'échec de la distribution. Sinon, l'objet de conversion directe (type) est plus rapide. Il faut plus de temps pour un transtypage direct pour lever une exception que pour retourner null.
Spence

15
Dans la même veine que le mot clé "as" ... le mot clé "is" est tout aussi utile.
dkpatt

28
Vous pouvez en abuser et avoir une NullReferenceException plus tard lorsque vous auriez pu avoir une InvalidCastException plus tôt.
Andrei Rînea

262

Deux choses que j'aime sont les propriétés automatiques afin que vous puissiez réduire encore plus votre code:

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

devient

public string Name { get; set;}

Aussi initialiseurs d'objets:

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

devient

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

6
Faut-il noter que les propriétés automatiques sont une fonctionnalité C # 3.0 uniquement?
Jared Updike

21
Les propriétés automatiques ont été introduites avec le compilateur 3.0. Mais comme le compilateur peut être défini pour produire du code 2.0, ils fonctionnent très bien. N'essayez simplement pas de compiler du code 2.0 avec des propriétés automatiques dans un ancien compilateur!
Joshua Shannon

74
Beaucoup de gens ne se rendent pas compte que get et set peuvent avoir une accessibilité différente, par exemple: public string Name {get; set privé;}
Nader Shirazie

7
Le seul problème avec les propriétés automatiques est qu'il ne semble pas possible de fournir une valeur d'initialisation par défaut.
Stein Åsmul

7
@ANeves: non ce n'est pas. A partir de cette page: Un DefaultValueAttribute ne provoquera pas l'initialisation automatique d'un membre avec la valeur de l'attribut. Vous devez définir la valeur initiale dans votre code. [DefaultValue]est utilisé pour le concepteur afin qu'il sache s'il faut afficher une propriété en gras (ce qui signifie non par défaut).
Roger Lipscombe

255

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

T t = default(T);

résulte en un 'null' 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.


4
Le plus: taper? comme raccourci pour Nullable <type>. default (int) == 0, mais default (int?) == null.
sunside


221

Le @ indique au compilateur d'ignorer tous 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 sera en fait imprimé comme (notez qu'il inclut même l'espace blanc utilisé pour l'indentation):

cat
             dog
             fish

la chaîne n'inclurait-elle pas tous les espaces que vous avez utilisés pour l'indentation?
andy

18
Oui, cela s'appelle une chaîne textuelle.
Joan Venge

4
Il serait plus clair si la sortie montrait également les espaces qui seraient imprimés. En ce moment, il semble que les nouveaux caractères des lignes soient imprimés mais les espaces sont ignorés.
aleemb le

Très utile pour échapper aux expressions régulières et aux longues requêtes SQL.
ashes999

Il aussi des cartes {{à {et }}à }rendre utile string.Format().
Ferruccio

220

Je pense que l'une des fonctionnalités les plus sous-estimées et moins connues de C # (.NET 3.5) sont les arbres d'expression , en particulier lorsqu'ils sont combinés avec des génériques et des Lambdas. Il s'agit d'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 l'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 courant de voir les développeurs faire cela avec des chaînes et des types (ou autre chose largement basé sur des chaînes):

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

Eh bien, ça craint à cause du manque de frappe forte. Et si je renomme "SomeMethod"? Maintenant, en 3.5 cependant, je peux le faire de 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 arbres d'expression en ce moment.


3
J'ai une classe utilitaire de réflexion qui fait de même avec FieldInfo, PropertyInfo, etc ...
Olmo

Oui, c'est super. J'ai pu utiliser des méthodes comme celle-ci pour écrire du code comme EditValue(someEmployee, e => e.FirstName);dans ma logique métier et le faire générer automatiquement toute la logique de plomberie pour un ViewModel et View pour modifier cette propriété (donc, une étiquette avec le texte "First Name" et une TextBox avec une liaison qui appelle le setter de la propriété FirstName lorsque l'utilisateur modifie le nom et met à jour la vue à l'aide du getter). Cela semble être la base de la plupart des nouvelles DSL internes en C #.
Scott Whitlock

4
Je pense que ce ne sont pas tant moins connus que moins compris.
Justin Morgan

Pourquoi devez-vous enregistrer une méthode? Je ne l'ai jamais utilisé auparavant - où et quand serait-il utilisé?
MoonKnight

209

« céder » me viendrait à l'esprit. Certains des attributs comme [DefaultValue ()] sont également parmi mes favoris.

Le mot-clé " var " est un peu plus connu, mais le fait que vous puissiez également l'utiliser dans les applications .NET 2.0 (tant que vous utilisez le compilateur .NET 3.5 et le définissez pour afficher le code 2.0) ne semble pas être très connu bien.

Edit: kokos, merci d'avoir souligné le ?? opérateur, c'est vraiment très utile. Comme il est un peu difficile de le rechercher sur Google (car ?? est simplement ignoré), voici la page de documentation MSDN pour cet opérateur: ?? Opérateur (référence C #)


14
La documentation de la valeur par défaut indique qu'elle ne définit pas vraiment la valeur de la propriété. Ce n'est qu'une aide pour les visualiseurs et les générateurs de code.
Boris Callens

2
Quant à DefaultValue: En attendant, certaines bibliothèques l'utilisent. ASP.net MVC utilise DefaultValue sur les paramètres d'une action de contrôleur (ce qui est très utile pour les types non nullables). À proprement parler, bien sûr, il s'agit d'un générateur de code car la valeur n'est pas définie par le compilateur mais par le code de MVC.
Michael Stum

6
Le nom du ?? L'opérateur est l'opérateur "Null Coalescing"
Armstrongest

le rendement est mon préféré, l'opérateur de fusion est cependant là-haut. Je ne vois rien sur CAS, ou la signature d'assembly, les noms forts, le GAC ... Je suppose que seul CAS est C # ... mais tant de développeurs n'ont aucune idée de la sécurité.
BrainSlugs83

198

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

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

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

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

encore une chose sur le type Nullable:

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

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


1
DateTime ne peut pas être défini sur null.
Jason Jackson

2
Alors, "int" est-il juste du sucre syntaxique C # pour System.Int32? Il existe en fait un support du compilateur construit autour des types Nullable, permettant de les définir sur null, par exemple (ce qui ne peut pas être fait en utilisant des structures génériques seules), et de les encadrer comme type sous-jacent.
P papa

4
@P Daddy - oui, int est du sucre syntaxique pour System.Int32. Ils sont complètement interchangeables, tout comme int? === Int32? === Nullable <Int32> === Nullable <int>
cjk

6
@ck: Oui, int est un alias pour System.Int32, comme T? est un alias pour Nullable <T>, mais ce n'est pas seulement du sucre syntaxique. C'est une partie définie de la langue. Les alias facilitent non seulement la lecture du code, mais conviennent également mieux à notre modèle. Exprimer Nullable <Double> en double? souligne la perspective selon laquelle la valeur ainsi contenue est (ou peut être) un double, pas seulement une structure générique instanciée sur le type Double. (suite)
P Daddy

3
... En tout cas, l'argument ne portait pas sur les alias (c'était juste une mauvaise analogie, je suppose), mais que les types nullables - en utilisant la syntaxe que vous préférez - sont en effet une fonctionnalité de langage, pas seulement un produit de génériques. Vous ne pouvez pas reproduire toutes les fonctionnalités de nullables (comparaison à / affectation de null, transfert d'opérateur, boxe de type sous-jacent ou null, compatibilité avec coalescence null et asopérateurs) avec des génériques seuls. Nullable <T> à lui seul est rudimentaire et loin d'être stellaire, mais le concept de types nullables dans le cadre du langage est kick ass.
P Daddy

193

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 une boxe / 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.

Les gens ne savent pas grand-chose sur System.WeakReference - une classe très utile qui garde la trace d'un objet mais permet toujours au garbage collector de le collecter.

La fonction "cachée" la plus utile serait le mot-clé return yield. 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 avec retard en générant une machine d'état sous le capot. Raymond Chen a récemment publié des détails sur les détails internes .


2
Plus de détails sur les mots clés non documentés de Peter Bromberg . Je ne comprends toujours pas s'il y a des raisons de les utiliser.
HuBeZa

@HuBeZa avec l'avènement des génériques, il n'y a pas (beaucoup?) De bonnes raisons d'utiliser __refType, __makeref et __refvalue. Ceux-ci ont été utilisés principalement pour éviter la boxe avant les génériques dans .NET 2.
Judah Gabriel Himango

Matt, avec l'introduction des génériques dans .NET 2, il n'y a pas de raison d'utiliser ces mots-clés, car leur objectif était d'éviter la boxe lors du traitement des types de valeur. Voir le lien par HuBeZa, et aussi voir codeproject.com/Articles/38695/UnCommon-C-keywords-A-Look#ud
Judah Gabriel Himango

185

Unions (du type mémoire partagée C ++) en C # pur et sûr

Sans recourir au mode et aux pointeurs non sécurisés, vous pouvez faire en sorte que les membres de la classe partagent l'espace mémoire dans une classe / structure. Étant donné la classe suivante:

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

Vous pouvez modifier les valeurs des champs d'octets en manipulant le champ Int32 et vice-versa. Par exemple, ce programme:

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

Produit ceci:

2147483647
FF FF FF 7F
65535

ajoutez simplement en utilisant System.Runtime.InteropServices;


7
@George, fait des merveilles lorsque vous communiquez avec des applications héritées via des sockets à l'aide de déclarations d'union c.
scottm

2
Il est également significatif de dire int et de flotter à l'offset 0. C'est ce dont vous avez besoin si vous voulez manipuler des nombres à virgule flottante comme des masques de bits, ce que vous voulez parfois. Surtout si vous voulez apprendre de nouvelles choses sur les nombres à virgule flottante.
John Leidegren

2
La chose ennuyeuse à ce sujet est que si vous allez utiliser ceci est une structure, le compilateur vous forcera à définir TOUTES les variables dans la fonction init. Donc, si vous avez: public A (int int32) {Int32 = int32; } il lancera "Le champ 'One' doit être entièrement assigné avant que le contrôle ne soit retourné à l'appelant", vous devez donc définir One = Two = Three = Four = 0; ainsi que.
manixrock

2
Cela a ses utilisations, principalement avec des données binaires. J'utilise une structure "Pixel" avec un int32 @ 0 et quatre octets pour les quatre composants @ 0, 1, 2 et 3. Idéal pour manipuler les données d'image rapidement et facilement.
snarf

57
Attention: cette approche ne prend pas en compte l'endianité. Cela signifie que votre code C # ne fonctionnera pas de la même manière sur toutes les machines. Sur les CPU peu endiens (qui stockent d'abord l'octet le moins significatif), le comportement affiché sera utilisé. Mais sur les processeurs big-endian, les octets sortiront inversés de ce que vous attendiez. Méfiez-vous de la façon dont vous l'utilisez dans le code de production - votre code peut ne pas être portable sur certains appareils mobiles et autres matériels, et peut se briser de manière non évidente (par exemple, deux fichiers apparemment dans le même format mais en fait avec l'ordre des octets inversé).
Ray Burns

176

Utilisation de @ pour les noms de variables qui sont des mots clés.

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

38
Pourquoi voudriez-vous utiliser un mot-clé comme nom de variable? Il me semble que cela rendrait le code moins lisible et obscurci.
Jon

41
Eh bien, la raison en est que CLI l'exige pour l'interopérabilité avec d'autres langages qui pourraient utiliser des mots clés C # comme noms de membres
Mark Cidade

69
Si vous avez déjà voulu utiliser les assistants HTML asp.net MVC et définir une classe HTML, vous serez heureux de savoir que vous pouvez utiliser @class afin qu'il ne soit pas reconnu comme mot
Boris Callens

31
Idéal pour les méthodes d'extension. DoSomething public static void (ce bar @this, string foo) {...}
Jonathan C Dickinson

45
@zihotki: Faux. var a = 5; Console.WriteLine (@a); Tirages 5
SLaks

168

Si vous souhaitez quitter votre programme sans appeler de blocs ou de finaliseurs enfin, utilisez FailFast :

Environment.FailFast()

12
Notez que cette méthode crée également un vidage de la mémoire et écrit un message dans le journal des erreurs Windows.
RickNZ

1
Il convient de noter qu'aucun finaliseur ou événement de déchargement de domaine d'application ne sera appelé lorsque cette méthode sera utilisée ...
AwkwardCoder

1
+1 pour l'indice, mais ce n'est pas C #, c'est BCL de .NET.
Abel

System.Diagnostics.Process.GetCurrentProcess (). Kill () est plus rapide
Tolgahan Albayrak

153

Renvoyer des types anonymes à partir d'une méthode et accéder aux membres sans réflexion.

// 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
Cela ne vous apporte vraiment rien. C'est en fait dangereux. Que faire si GetUserTuple est modifié pour renvoyer plusieurs types? Le cast échouera au moment de l'exécution. Une des grandes choses à propos de C # /. Net est la vérification du temps de compilation. Il serait préférable de simplement créer un nouveau type.
Jason Jackson

9
@Jason J'ai dit que ce n'était probablement pas utile mais c'est surprenant (et je pensais caché).
denis phillips

31
Bien que cool, cela semble être un choix de conception plutôt médiocre. Vous avez essentiellement défini le type anonyme à deux endroits. À ce stade, il suffit de déclarer une vraie structure et de l'utiliser directement.
Paul Alexander

6
@George: une telle convention s'appellerait une ... struct?
R. Martinho Fernandes

2
cette astuce est nommée «cast by sample» et ne fonctionnera pas si la méthode qui renvoie un type anonyme se trouve dans un autre assembly.
desco

146

En voici une utile pour les expressions régulières et les chemins de fichiers:

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

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


27
De plus, une constante @ accepte les sauts de ligne à l'intérieur. Parfait lors de l'attribution d'un script multiligne à une chaîne.
Tor Haugen

11
N'oubliez pas également d'échapper à un guillemet, il suffit de les doubler, en d'autres termes. [code] var candy = @ "J'aime" "rouge" "les cannes de bonbon."; [/ code]
Dave

5
J'ai tendance à construire des chemins avec Path.Combine. J'utilise définitivement le @ pour regex!
Dan McClain

6
@new est également une variable au lieu d'un mot clé: @this, @int, @return, @interface ... ainsi de suite :)
IAbstract

Celui-ci ne se rapproche pas: Mais quelles sont les fonctionnalités ou les astuces les plus cachées de C # que même les fans de C #, les toxicomanes, les experts connaissent à peine?
publicgk

141

Mixins. Fondamentalement, si vous souhaitez ajouter une fonctionnalité à plusieurs classes, mais ne pouvez pas utiliser une classe de base pour toutes, demandez à chaque classe d'implémenter une interface (sans membres). Ensuite, écrivez une méthode d'extension pour l'interface , ie

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

Bien sûr, une certaine clarté est sacrifiée. Mais ça marche!


4
Oui, je pense que c'est le vrai pouvoir des méthodes d'extension. Ils permettent essentiellement la mise en œuvre de méthodes d'interface.
John Bubriski

Ceci est également pratique si vous utilisez NHibernate (ou Castle ActiveRecord) et que vous devez utiliser des interfaces pour vos collections. De cette façon, vous pouvez donner un comportement aux interfaces de collecte.
Ryan Lundy

C'est essentiellement ainsi que toutes les méthodes LINQ sont implémentées, pour mémoire.
WCWedin

Voici un lien qui parle de ce que j'ai mentionné ci-dessus, en utilisant des méthodes d'extension avec des interfaces de collecte dans NHibernate ou Castle ActiveRecord: devlicio.us/blogs/billy_mccafferty/archive/2008/09/03/…
Ryan Lundy

7
Si seulement ils permettaient des propriétés d'extension !!!! Je détestais devoir écrire une méthode d'extension qui implorait d'être une propriété en lecture seule ....
John Gibb

130

Je ne sais pas pourquoi quelqu'un voudrait utiliser Nullable <bool>. :-)

Vrai, faux, FileNotFound ?


87
si un utilisateur répond à une question oui non, alors null serait approprié si la question n'a pas été répondue
Omar Kooheji

22
Les types nullables sont pratiques pour l'interaction avec une base de données où les colonnes de table sont souvent nullables.
tuinstoel

11
Oui, non, Maybee?
Dan Blair

21
Stocker les valeurs d'un CheckBox à trois états
Shimmy Weitzhandler

8
Comme dans SQL: Oui / non / inconnu.
erikkallen

116

Celui-ci n'est pas «caché» autant qu'il est mal nommé.

Une grande attention est accordée aux algorithmes "carte", "réduire" et "filtrer". Ce que la plupart des gens ne réalisent pas, c'est que .NET 3.5 a ajouté ces trois algorithmes, mais cela leur a donné des noms très SQL, basés sur le fait qu'ils font partie de LINQ.

"map" => Sélectionnez
Transforme les données d'un formulaire à un autre

"réduire" => Agréger
Agrège les valeurs en un seul résultat

"filter" => Où
Filtre les données en fonction d'un critère

La possibilité d'utiliser LINQ pour effectuer un travail en ligne sur des collections qui prenaient auparavant des itérations et des conditions peut être extrêmement utile. Il vaut la peine d'apprendre comment toutes les méthodes d'extension LINQ peuvent aider à rendre votre code beaucoup plus compact et maintenable.


1
Select agit également comme la fonction "retour" dans les monades. Voir stackoverflow.com/questions/9033/hidden-features-of-c#405088
Mark Cidade

1
L'utilisation de "select" n'est requise que si vous utilisez la syntaxe SQLish. Si vous utilisez la syntaxe de la méthode d'extension - someCollection.Where (item => item.Price> 5.99M) - l'utilisation des instructions select n'est pas requise.
Brad Wilson

7
@Brad, c'est (où) est une opération de filtrage. Essayez de faire une opération de carte sans sélectionner ...
Eloff

2
LINQ est la grande chose qui est arrivée à C # à mon avis: stackoverflow.com/questions/2398818/…
Leniel Maccaferri

1
La plus petite signature de l'agrégat est la fonction "réduire", la signature du milieu de l'agrégat est la fonction "plier" beaucoup plus puissante!
Brett Widmeier

115
Environment.NewLine

pour les sauts de ligne indépendants du système.


10
La chose ennuyeuse à propos de celui-ci, c'est qu'il n'est pas inclus dans le cadre compact.
Stormenet

14
Cela vaut la peine de souligner que cela est spécifique à la plate-forme hôte de l'application - donc si vous créez des données destinées à un autre système, vous devez utiliser \ n ou \ r \ n de manière appropriée.
Mesh

Cela fait partie de la BCL de .NET, pas une fonctionnalité de C # en soi.
Abel

111

Si vous essayez d'utiliser des accolades à l'intérieur d'une expression 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: En fait, oui, ce sont des accolades, mais "accolades" est un nom alternatif pour eux. [et ]sont des crochets et <et >sont des crochets. Voir en.wikipedia.org/wiki/Bracket .
icktoofay

4
Vous avez raison. Mais quand j'ai commenté, il n'a pas dit entre crochets "bouclés".
Ryan Lundy

2
Très agréable à signaler. Rappelez-vous que mon premier String.Format ressemblait à: String.Format ("{0} je suis entre accolades {1} {2} {3}", "{", "}", 3, "souris aveugles"); Une fois que j'ai découvert que les échapper se faisait en utilisant {{et}} j'étais tellement heureux :)
Gertjan

Muahahahaa ... Programmation déjà 3 ans en .Net et je ne connaissais pas celui-ci. : D
Arnis Lapsa

crochets "bouclés" agissant de manière similaire aux séquences d'échappement ??
Pratik

104
  1. ?? - opérateur coalescent
  2. using ( statement / directive ) - excellent mot-clé qui peut être utilisé pour plus que simplement appeler Dispose
  3. en lecture seule - devrait être utilisé davantage
  4. netmodules - dommage qu'il n'y ait pas de support dans Visual Studio

6
using peut également être utilisé pour alias un long espace de noms vers une chaîne plus pratique, c'est-à-dire: using ZipEncode = MyCompany.UtilityCode.Compression.Zip.Encoding; Il y a plus ici: msdn.microsoft.com/en-us/library/sf0df423.aspx
Dave R.

2
Ce n'est vraiment pas la même chose. Lorsque vous appelez Dispose, vous pouvez utiliser l'instruction using, lorsque vous aliasez des types, vous utilisez une directive using.
Øyvind Skaar

2
Juste au cas où vous voudriez un nom # 1 (comme vous l'avez fait avec l'opérateur ternaire), ?? est appelé l'opérateur de coalescence nul.
J. Steen

4
@LucasAardvark: Comme J Steen l'a mentionné, cela s'appelle l'opérateur de coalescence nulle. Cherchez ça!
kokos

1
Rechercher ?? opérateur chez google try: google.com/search?q=c%23+%3F%3F+operator
backslash17

103

@Ed, je suis un peu réticent à publier ceci, car c'est un peu plus que de taquiner. Cependant, je voudrais souligner que dans votre exemple de code:

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

Si vous allez utiliser «is», pourquoi le suivre avec un casting sûr en utilisant «as»? Si vous avez vérifié que obj est bien MyClass, un casting standard:

c = (MyClass)obj

... ne va jamais échouer.

De même, vous pourriez simplement dire:

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

Je n'en sais pas assez sur les entrailles de .NET pour être sûr, mais mon instinct me dit que cela réduirait un maximum de deux opérations de conversion de type à un maximum. Il est peu probable de casser la banque de traitement de toute façon; personnellement, je pense que cette dernière forme semble plus propre aussi.


16
Si le casting est du type exact (cast à "A" lorsque l'objet est "A", pas dérivé de celui-ci), le cast droit est ~ 3x PLUS RAPIDE que "as". Lors de la conversion d'un type dérivé (conversion en "A" lorsque l'objet est "B", qui dérive de "A"), la conversion droite est ~ 0,1 fois plus lente que "en tant que". "est", puis "comme" est tout simplement idiot.
P Papa

2
Non, mais vous pouvez écrire "if ((c = obj as MyClass)! = Null)".
Dave Van den Eynde

10
iset asne fera pas de cast utilisateur. Ainsi, le code ci-dessus demande à l' isopérateur si obj est dérivé de MyClass (ou a une distribution définie implicitement par le système). , Également iséchoue sur null. Ces deux cas marginaux peuvent être importants pour votre code. Par exemple, vous voudrez peut-être écrire: if( obj == null || obj is MyClass ) c = (MyClass)obj; Mais ceci est strictement différent de: try { c = (MyClass)obj; } catch { }puisque le premier n'effectuera aucune conversion définie par l'utilisateur, mais le second le fera. Sans le nullcontrôle, l'ancien sera pas non plus mis cen objest null.
Adam Luter

2
En IL, un transtypage va vers une CASTCLASS mais une as / is va vers une instruction ISINST.
John Gibb

5
J'ai effectué un test pour cela, en lançant IEnumerable<int>vers List<int>et en lançant object( new object()) vers IEnumerable<int>, pour m'assurer qu'il n'y a pas d'erreurs: distribution directe: 5,43 ns, is-> en tant que distribution: 6,75 ns, en tant que distribution: 5,69 ns. Puis test des castes invalides: cast direct: 3125000ns, comme cast: 5.41ns. Conclusion: arrêtez de vous soucier du facteur 1%, et assurez-vous simplement que vous utilisez est / comme lorsque le cast peut être invalide, car les exceptions (également si elles sont gérées) sont TRÈS lentes par rapport au casting, nous parlons d'un facteur 578000 plus lent. Rappelez-vous que la dernière partie, le reste n'a pas d'importance (.Net FW 4.0, build build)
Aidiakapi

98

Peut-être pas une technique avancée, mais celle que je vois tout le temps qui me rend fou:

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

peut être condensé en:

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

10
L'opérateur ternaire a été banni de mon groupe. Certaines personnes n'aiment pas ça, même si je n'ai jamais compris pourquoi.
Justin R.

13
Je suppose que ce ne sont pas les mêmes choses, être un opérateur et non une déclaration. Je préfère la première approche moi-même. Il est plus cohérent et facilement extensible. Les opérateurs ne peuvent pas contenir d'instructions, donc à la minute où vous devez agrandir le corps, vous devrez convertir cet opérateur ternaire en une instruction if
kervin

16
peut être condensé en x ++; Ok c'est inutile ^^
François

5
@Guillaume: pour tenir compte de toutes les valeurs de x: x = 2 + System.Math.Min (1, System.Math.Abs ​​(x-1));
mbeckish

38
Il est en fait appelé "opérateur conditionnel" - c'est un opérateur ternaire car il prend trois arguments. en.wikipedia.org/wiki/Conditional_operator
Blorgbeard est sorti le
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.