C#反模式

时间:2009-10-07 05:12:42

标签: c# anti-patterns

简而言之:我发现Java antipatterns是不可或缺的资源。适合初学者和专业人士。我还没有为C#找到这样的东西。所以我将这个问题作为社区维基开放,并邀请所有人分享他们对此的了解。由于我是C#的新手,我对此非常感兴趣,但不能从一些反模式开始:/

以下是我认为特别适用于C#而非其他语言的答案。

我只是复制/粘贴这些!考虑一下这些评论。


Throwing NullReferenceException

抛出错误的异常:

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

Properties vs. public Variables

类中的公共变量(改为使用属性)。

除非,否则该类是一个简单的数据传输对象。


Not understanding that bool is a real type, not just a convention

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

或者,甚至更好

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

这些构造经常被CC++开发人员使用,其中布尔值的概念只是一个约定(0 == false,其他任何都是真的);在C#或其他具有真正布尔值的语言中,这不是必需的(或可取的)。


Using using()

在适当情况下不使用using

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.

38 个答案:

答案 0 :(得分:62)

错误地重新抛出异常。要重新抛出异常:

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
}

答案 1 :(得分:40)

GC.Collect()收集而不是信任垃圾收集器。

答案 2 :(得分:30)

我在Java和C#中都看到了这种方式太多了......

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

如果还有奖励积分

else{
  somethingelse = false;
}

答案 3 :(得分:25)

using Microsoft.SharePoint;

'努夫说

答案 4 :(得分:22)

我看了很多代码:

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

应该是:

       return (i==3);

答案 5 :(得分:17)

侮辱德米特法则:

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

答案 6 :(得分:17)

投掷NullReferenceException

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

答案 7 :(得分:16)

我是亲眼看到的。

public object GetNull()
{
     return null;
}

它实际上是在应用程序中使用的,甚至还有一个存储过程也可以使用它,sp_GetNull将返回null ....

这是我的一天。

我认为sp用于经典的asp网站..与结果集有关。 .net的一个想法是将代码“转换”成.net ...

答案 8 :(得分:14)

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

或者更一般的情况:

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

答案 9 :(得分:12)

我在我们的项目中发现了这个并且几乎打破了主席......

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

答案 10 :(得分:11)

我经常偶然发现这种滥用行为:

var ok = Bar();

甚至更好:

var i = AnyThing();

以这种方式使用var是没有意义的,也没有任何收获。它只会使代码更难以遵循。

答案 11 :(得分:10)

答案 12 :(得分:10)

不理解bool是一个真正的类型,而不仅仅是一个约定

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

或者,甚至更好

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

这些构造经常被CC++开发人员使用,其中布尔值的概念只是一个约定(0 == false,其他任何都是真的);在C#或其他具有真正布尔值的语言中,这不是必需的(或可取的)。

已更新:重新提及最后一段以提高其清晰度。

答案 13 :(得分:9)

类中的公共变量(改为使用属性)。

除非,否则该类是一个简单的数据传输对象。

请参阅以下评论以供讨论和澄清。

答案 14 :(得分:8)

我实际上看过这个。

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

击败isAvailable == true反模式手! 使这成为一种超级反模式!

答案 15 :(得分:6)

两串反模式
反模式#1
检查字符串是否为空或为空

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

//Good
string.IsNullOrEmpty(myString)

反模式#2 (仅适用于.NET 4.0)
检查字符串是否为空或空格或空格

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

//Good
string.IsNullOrWhiteSpace(myString) 

答案 16 :(得分:6)

私有自动实施的属性:

private Boolean MenuExtended { get; set; }

答案 17 :(得分:6)

在每个方法的顶部声明并初始化所有局部变量是如此丑陋!

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

    // Code
}

答案 18 :(得分:6)

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.

答案 19 :(得分:5)

if(data != null)
{
  variable = data;
}
else
{
  variable = new Data();
}

可以更好地写成

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

甚至更好地写成

variable = data ?? new Data();

最后一个代码清单适用于.NET 2.0及以上版本

答案 20 :(得分:5)

不必要的投射(请相信编译器):

foreach (UserControl view in workspace.SmartParts)
{
  UserControl userControl = (UserControl)view;
  views.Add(userControl);
}

答案 21 :(得分:4)

说起口音总能抓住我。

C ++程序员:

if (1 == variable) { }

在C#中,如果你输入if (1 = variable),这会给你一个编译错误,允许你按照你的意思编写代码而不用担心自己在脚下射击。

答案 22 :(得分:4)

不使用三元是我看到偶尔转换为c#的东西

你知道了:

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

而不是:

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

答案 23 :(得分:3)

Accessing modified closures

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

(参见链接以获得解释和修复)

答案 24 :(得分:3)

使用字符串连接而不是字符串构建器连接任意数量的字符串

Exampls

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

答案 25 :(得分:2)

我正在进行的项目有五十个类,都是从同一个类继承的, all 定义了:

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

将它放在父类中,或者放在旁边的实用程序类中。哎呀。

您是否考虑过浏览The Daily WTF

答案 26 :(得分:2)

这被认为是一般性的吗?

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

我不知道如何解释它,但它就像有人捕获异常并一遍又一遍地重试代码,希望它能够在以后工作。就像发生IOException一样,他们只是反复尝试直到它工作..

答案 27 :(得分:1)

在我继承的系统中发现了几次......

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

反之亦然

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

答案 28 :(得分:1)

大量过于复杂的'Page_Load'方法,它们想要做所有事情。

答案 29 :(得分:1)

将属性用于除了简单地检索值或可能是廉价计算之外的任何其他内容。如果要从属性访问数据库,则应将其更改为方法调用。开发人员希望方法调用可能成本高昂,他们不希望这些属性。

答案 30 :(得分:1)

我之前有过这个:

AnEnum e = AnEnum.Abc;
int i = (int)e;
// lots of code
AnEnum f = (AnEnum)Enum.Parse(i, typeof(AnEnum));

答案 31 :(得分:1)

if (state == ((int)RowState.Active).ToString())
else if (state == ((int)RowState.NotActive).ToString())

state是一个字符串post值,包含枚举RowState的值。

最终,这是我们用来检查价值的方式。

答案 32 :(得分:1)

.NET的主要问题似乎是有许多开发人员来自VB 6.0或者(在我看来更糟糕的是,因为他们错误地认为他们知道该怎么做而VB 6.0程序员至少足够谦虚愿意学习新东西)Java / C ++。

人们对现代范式一无所知,人们用最糟糕的C ++风格涂抹丑陋的P / Invoke代码。 : - (

答案 33 :(得分:0)

无知是幸福(了解你的框架):

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

int daysLeft = keyDays.Days - nowDays.Days;

答案 34 :(得分:0)

编码属性时,只需自动给它一个getter和setter而不考虑它的使用。通常不使用get或set,只应读取(get)或写入(set)属性。

答案 35 :(得分:0)

我最近刚看了几个。

永远不会结束参数链

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
    }

想知道关闭表单会发生什么

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

Stringly Typed

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;

答案 36 :(得分:0)

使用(坏)

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

而不是(好)

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

测试IEnumerable是否包含任何内容。 Count()必须使用MoveNext()枚举整个集合,而Any()只需拨打MoveNext()一次。

答案 37 :(得分:-2)

过度使用/滥用对象初始值设定项,可能是因为懒惰:

var person = new Person
{
    FirstName = "joe",
    (... lots of setters down here)
};

没有意识到这几乎几乎就像将所有字段公开一样糟糕。您应该始终注意创建一些有效的构造函数,将对象初始化为有效状态。