web-dev-qa-db-fra.com

Antipatterns C #

Pour faire court: je trouve que les Java antipatterns une ressource indispensable. Pour les débutants autant que pour les professionnels. Je n'ai pas encore trouvé quelque chose comme ça pour C #. Je vais donc ouvrir cette question en tant que wiki communautaire et inviter tout le monde à partager ses connaissances à ce sujet. Comme je suis nouveau sur C #, je suis fortement intéressé par cela, mais je ne peux pas commencer avec quelques antipatterns: /

Voici les réponses que je trouve spécifiquement vraies pour C # et pas pour les autres langages.

Je viens de copier/coller ces derniers! Pensez également à jeter un œil sur les commentaires à ce sujet.


Lancer NullReferenceException

Lancer la mauvaise exception:

if (FooLicenceKeyHolder == null)
    throw new NullReferenceException();

Propriétés vs Variables publiques

Variables publiques dans les classes (utilisez plutôt une propriété).

Sauf si la classe est un simple objet de transfert de données.


Ne pas comprendre que bool est un vrai type, pas seulement une convention

if (myBooleanVariable == true)
{
    ...
}

ou encore mieux

if (myBooleanVariable != false)
{
    ...
}

De telles constructions sont souvent utilisées par les développeurs C et C++ Où l'idée d'une valeur booléenne n'était qu'une convention (0 == false, tout le reste est vrai); ce n'est pas nécessaire (ou souhaitable) en C # ou dans d'autres langages qui ont de vrais booléens.


en utilisant using()

Ne pas utiliser using le cas échéant:

object variable;
variable.close(); //Old code, use IDisposable if available.
variable.Dispose(); //Same as close.  Avoid if possible use the using() { } pattern.
variable = null; //1. in release optimised away.  2. C# is GC so this doesn't do what was intended anyway.
55
exhuma

Retournement incorrect de l'exception. Pour renvoyer une exception:

try
{
    // do some stuff here
}
catch (Exception ex)
{
    throw ex;  // INCORRECT
    throw;     // CORRECT
    throw new Exception("There was an error"); // INCORRECT
    throw new Exception("There was an error", ex); // CORRECT
}
62
rein

GC.Collect() à collecter au lieu de faire confiance au garbage collector.

40
Andrew Keith

Je vois trop cette façon, à la fois en Java et C # ...

if(something == true){
  somethingelse = true;
}

avec des points bonus si elle a également

else{
  somethingelse = false;
}
30
sstewart
using Microsoft.SharePoint;

dit Nuff

25
Rubens Farias

Je vois beaucoup de code suivant:

if (i==3)
       return true;
else
       return false;

devrait être:

       return (i==3);
22
Benny

Insulter la loi de Déméter:

a.PropertyA.PropertyC.PropertyB.PropertyE.PropertyA = 
     b.PropertyC.PropertyE.PropertyA;
17
leppie

Lancer NullReferenceException:

if (FooLicenceKeyHolder == null)
    throw new NullReferenceException();
17
leppie

C'est vrai, je l'ai vu de mes propres yeux.

public object GetNull()
{
     return null;
}

Il était en fait utilisé dans l'application, et avait même une procédure stockée pour l'accompagner aussi, un sp_GetNull qui retournerait null ....

qui a fait ma journée.

Je pense que le sp a été utilisé pour un site asp classique .. quelque chose à voir avec un ensemble de résultats. celui de .net était une idée de quelqu'un de "convertir" le code en .net ...

16
dmportella
int foo = 100;
int bar = int.Parse(foo.ToString());

Ou le cas plus général:

object foo = 100;
int bar = int.Parse(foo.ToString());
14
leppie

J'ai trouvé cela dans notre projet et j'ai presque cassé la chaise ...

DateTime date = new DateTime(DateTime.Today.Year, 
                             DateTime.Today.Month, 
                             DateTime.Today.Day);
12
Adriaan Stander

Très souvent, je tombe sur ce type de var-abuse:

var ok = Bar();

ou encore mieux:

var i = AnyThing();

Utiliser var de cette façon n'a aucun sens et ne rapporte rien. Cela rend simplement le code plus difficile à suivre.

11
10
anthony

Ne pas comprendre que le bool est un vrai type, pas seulement une convention

if (myBooleanVariable == true)
{
    ...
}

ou encore mieux

if (myBooleanVariable != false)
{
    ...
}

Des constructions comme celles-ci sont souvent utilisées par C et C++ développeurs où l'idée d'une valeur booléenne n'était qu'une convention (0 == false, tout le reste est vrai); ce n'est pas nécessaire (ou souhaitable) en C # ou dans d'autres langages qui ont de vrais booléens.

mis à jour: reformulé le dernier paragraphe pour améliorer sa clarté.

10
Bevan

Variables publiques dans les classes (utilisez plutôt une propriété).

Sauf la classe est un simple objet de transfert de données.

Voir les commentaires ci-dessous pour discussion et clarification.

9
Robert Harvey

J'ai vraiment vu ça.

bool isAvailable = CheckIfAvailable();
if (isAvailable.Equals(true))
{ 
   //Do Something
}

bat le isAvailable == true anti-motif haut la main!
En faisant un super-anti-motif!

8
Binoj Antony
object variable;
variable.close(); //Old code, use IDisposable if available.
variable.Dispose(); //Same as close.  Avoid if possible use the using() { } pattern.
variable = null; //1. in release optimised away.  2. C# is GC so this doesn't do what was intended anyway.
6
Spence

Propriétés privées implémentées automatiquement:

private Boolean MenuExtended { get; set; }
6
leppie

Deux cordes anti motifs
Anti-Pattern # 1
Vérification des chaînes nulles ou vides

//Bad
if( myString == null || myString == "" )
OR
if( myString == null || myString.Length == 0 )

//Good
string.IsNullOrEmpty(myString)

Anti-Pattern # 2 (uniquement pour .NET 4.0)
Vérification des chaînes pour un espace nul, vide ou blanc

//Bad
if( myString == null || myString == "" || myString.Trim() == "")

//Good
string.IsNullOrWhiteSpace(myString) 
6
Binoj Antony

Déclarer et initialiser toutes les variables locales en haut de chaque méthode est si moche!

void Foo()
{
    string message;
    int i, j, x, y;
    DateTime date;

    // Code
}
6

Casting inutile (faites confiance au compilateur):

foreach (UserControl view in workspace.SmartParts)
{
  UserControl userControl = (UserControl)view;
  views.Add(userControl);
}
5
leppie
if(data != null)
{
  variable = data;
}
else
{
  variable = new Data();
}

peut être mieux écrit comme

variable = (data != null) ? data : new Data();

et encore mieux écrit

variable = data ?? new Data();

La dernière liste de codes fonctionne dans .NET 2.0 et supérieur

5
Binoj Antony

Parler avec un accent m'a toujours attiré.

Programmeurs C++:

if (1 == variable) { }

En C #, cela vous donnera une erreur de compilation si vous deviez taper if (1 = variable), vous permettant d'écrire le code comme vous l'entendez au lieu de vous soucier de vous tirer une balle dans le pied.

4
Spence

Ne pas utiliser le ternaire est quelque chose que je vois se convertir en c # faire de temps en temps

tu vois:

private string foo = string.Empty;
if(someCondition)
  foo = "fapfapfap";
else
  foo = "squishsquishsquish";

au lieu de:

private string foo  = someCondition ? "fapfapfap" : "squishsquishsquish";
4
IanStallings

Pour concaténer un nombre arbitraire de chaînes en utilisant la concaténation de chaînes au lieu de stringbuilder

Exemple

foreach (string anItem in list)
    message = message + anItem;
3
Kaz

Accès aux fermetures modifiées

foreach (string list in lists)
{
        Button btn = new Button();
        btn.Click += new EventHandler(delegate { MessageBox.Show(list); });
}

(voir le lien pour l'explication et le correctif)

3
Greg

est-ce considéré comme général?

public static main(string [] args)
{
  quit = false;
  do
  {
  try
  {
      // application runs here .. 
      quit = true;
  }catch { }
  }while(quit == false);
}

Je ne sais pas comment l'expliquer, mais c'est comme si quelqu'un attrapait une exception et réessayait le code encore et encore en espérant que cela fonctionne plus tard. Comme si une IOException se produisait, ils essayaient encore et encore jusqu'à ce que cela fonctionne.

2
Andrew Keith

Le projet sur lequel je travaillais avait cinquante classes, toutes héritant de la même classe, que toutes définissaient:

public void FormatZipCode(String zipCode) { ... }

Soit le mettre dans la classe parent, soit une classe utilitaire sur le côté. Argh.

Avez-vous envisagé de parcourir The Daily WTF ?

2
Dean J

J'ai trouvé cela plusieurs fois dans un système dont j'ai hérité ...

if(condition){
  some=code;
}
else
{
  //do nothing
}

et vice versa

if(condition){
  //do nothing
}
else
{
  some=code;
}
1
Andrew

Méthodes de'▶Load 'massivement trop compliquées, qui veulent tout faire.

1
Ralph Lavelle

J'ai déjà eu celui-ci:

AnEnum e = AnEnum.Abc;
int i = (int)e;
// lots of code
AnEnum f = (AnEnum)Enum.Parse(i, typeof(AnEnum));
1
Darko Z
if (state == ((int)RowState.Active).ToString())
else if (state == ((int)RowState.NotActive).ToString())

state est une chaîne de valeur qui contient une valeur de l'énumération RowState.

En fin de compte, c'est la façon dont nous utilisons pour vérifier la valeur.

1
Fitzchak Yitzchaki

Utiliser des propriétés pour autre chose que pour simplement récupérer une valeur ou éventuellement un calcul peu coûteux. Si vous accédez à une base de données depuis votre propriété, vous devez la remplacer par un appel de méthode. Les développeurs s'attendent à ce que les appels de méthode soient coûteux, ils n'attendent pas cela des propriétés.

1
triskelion

Le principal problème avec .NET semble être le fait qu'il existe de nombreux développeurs provenant de VB 6.0 ou (pire encore à mon avis, car ils croient à tort qu'ils savent quoi faire pendant que VB Les programmeurs 6.0 sont au moins assez humbles pour vouloir apprendre quelque chose de nouveau) Java/C++.

Des gens trop ignorants des paradigmes modernes, des gens en train de plâtrer leur code avec un laid P/Invoke dans le pire style C++ possible. :-(

1

L'ignorance est un bonheur (connaissez votre cadre):

TimeSpan keyDays = new TimeSpan(Licence.LicenceExpiryDate.Ticks);
TimeSpan nowDays = new TimeSpan(System.DateTime.Now.Ticks);

int daysLeft = keyDays.Days - nowDays.Days;
0
leppie

Utilisation (mauvaise)

IEnumerable<Bar> foo = ...
if (foo.Count() > 0)
{
    ...
}

au lieu de (bon)

IEnumerable<Bar> foo = ...
if (foo.Any())
{
    ...
}

pour tester si un IEnumerable contient quelque chose. Count() doit énumérer l'ensemble de la collection avec MoveNext(), tandis que Any() n'a à appeler MoveNext() qu'une seule fois.

0
Mark Nelson

Je viens d'en voir quelques-uns récemment.

ne terminant jamais la chaîne de paramètres

public string CreateJob(string siteNumber, string customer, string jobType, string description, string reference, string externalDoc, string enteredBy, DateTime enteredDateTime)
    {
        //recordtype = 0 for job
        //load assignments and phases set to false
        return Create(0, siteNumber, customer, jobType, description, reference, externalDoc, enteredBy, enteredDateTime, false, false);
    }

public string Create(int recordType, string siteNumber, string customer, string jobType, string description, string reference, string externalDoc, string enteredBy, DateTime enteredDateTime, bool loadAssignments, bool loadPhases)
{
    _vmdh.Fields.FieldByName("WDDOCTYPE").SetValue(recordType, false);
    _vmdh.Fields.FieldByName("NMDOCID").SetValue(-1, false);
    _vmdh.Init();           
        ....
        ...
        // And it keeps going
    }

Je me demande ce qui se passe à la fermeture du formulaire

 private void frmAddImages_FormClosing(object sender, FormClosingEventArgs e)
{
    if (DialogResult != DialogResult.OK)
    {
        if (IsDirty)
        {
            e.Cancel = !(MessageBox.Show("Are you sure that you want to exit without saving", "Form Not Saved", MessageBoxButtons.YesNo) == DialogResult.Yes);
        }
    }
    }

tapé en chaîne

switch (cbDateFilter.Text)
            {
                case "This Week":
                    dt = DateTime.Now;
                    while (dt.DayOfWeek != DayOfWeek.Monday) dt = dt.AddDays(-1); //find first day of week
                    dtFrom.Value = DateTime.Parse(dt.ToString("dd/MM/yyyy 00:00:00"));
                    dtTo.Value = DateTime.Parse(dt.AddDays(6).ToString("dd/MM/yyyy 23:59:59"));
                    break;

                case "This Month":
                    dt = DateTime.Now;
                    while (dt.Day != 1) dt = dt.AddDays(-1); // find first day of month
                    dtFrom.Value = DateTime.Parse(dt.ToString("dd/MM/yyyy 00:00:00"));
                    dtTo.Value = DateTime.Parse(dt.AddMonths(1).AddDays(-1).ToString("dd/MM/yyyy 23:59:59"));
                    break;

                case "This Quarter":
                    // if at end of Quarter then we need subtract -4 to get to priv Quarter
                    dt = DateTime.Now;
                    while (dt.Month != 7 &&
                        dt.Month != 10 &&
                        dt.Month != 1 &&
                        dt.Month != 4) dt = dt.AddMonths(-1); //find first month, fiscal year
                    while (dt.Day != 1) dt = dt.AddDays(-1); // find first day on month
                    dtFrom.Value = DateTime.Parse(dt.ToString("dd/MM/yyyy 00:00:00"));
                    dtTo.Value = DateTime.Parse(dt.AddMonths(3).AddDays(-1).ToString("dd/MM/yyyy 23:59:59"));
                    break;
0
Raghu

Lors du codage d'une propriété, il suffit de lui donner automatiquement un getter et un setter sans penser à son utilisation. Souvent, get ou set n'est pas utilisé et la propriété doit être en lecture (get) uniquement ou en écriture (set) uniquement.

0
bytedev