C#反模式

exh*_*uma 55 c# anti-patterns

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

以下是我发现C#而不是其他语言的答案.

我只是复制/粘贴这些!考虑看看这些评论.


投掷 NullReferenceException

抛出错误的异常:

if (FooLicenceKeyHolder == null)
    throw new NullReferenceException();
Run Code Online (Sandbox Code Playgroud)

属性与公共变量

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

除非该类是一个简单的数据传输对象.


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

if (myBooleanVariable == true)
{
    ...
}
Run Code Online (Sandbox Code Playgroud)

或者,甚至更好

if (myBooleanVariable != false)
{
    ...
}
Run Code Online (Sandbox Code Playgroud)

这样的结构通常使用CC++开发,其中一个布尔值的想法只是一个约定(0 ==假的,什么都为true); 在C#或其他具有真正布尔值的语言中,这不是必需的(或可取的).


运用 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.
Run Code Online (Sandbox Code Playgroud)

rei*_*ein 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
}
Run Code Online (Sandbox Code Playgroud)

  • `catch(Exception ex)`本身就是一种反模式. (31认同)
  • @Joren,catch(Exception ex)没有throw是一个反模式......如果你扔回来有很多有效案例来捕获常规异常类型(比如,记录,抛出一个新的异常类型,对某些进行回滚)资源等).但当然规则因应用程序,库,插件等而异. (18认同)
  • 如果要隐藏原始错误(例如库),可能与安全相关,则抛出新异常("有错误")可能完全有效. (5认同)

And*_*ith 40

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

  • 并且无法等待待处理的终结器完成,在极少数情况下你想要强制收集. (12认同)
  • GC.Collect()有一些有效的用例,但在典型的应用程序中几乎没有.你需要特别使用.Net来调用GC.Collect()(就像一个游戏引擎,在加载一个级别后,所以GC不会在级别中间启动进行完全收集,收集以前级别分配的对象)或者近实时应用程序,其中GC行为需要在某种程度上受到控制和可预测,或者当您知道自己将在一段时间内闲置并使用该机会进行收集时,服务器应用程序. (6认同)
  • 您可以获得OutOfMemoryException以获取碎片引用或请求系统上的更多内存.您是否有机会确定您的页面文件大小?我的意思是,如果你认为你可以写一个比微软更好的垃圾收集器我会说它去,然后让他们从你那里购买它. (4认同)

小智 30

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

if(something == true){
  somethingelse = true;
}
Run Code Online (Sandbox Code Playgroud)

如果它也有奖励积分

else{
  somethingelse = false;
}
Run Code Online (Sandbox Code Playgroud)

  • 对于第一种情况,请考虑something = false和somethingelse = true的情况.你不应该重构某些东西 (9认同)
  • @vanya:当然不是.那是'somethingelse | = something`. (8认同)
  • 如果没有奖金,那就不那么痛苦了(只有"== true") (4认同)

Rub*_*ias 25

using Microsoft.SharePoint;
Run Code Online (Sandbox Code Playgroud)

'努夫说


Ben*_*nny 22

我看到以下代码:

if (i==3)
       return true;
else
       return false;
Run Code Online (Sandbox Code Playgroud)

应该:

       return (i==3);
Run Code Online (Sandbox Code Playgroud)

  • `return`不是**函数.括号是不必要的. (29认同)
  • @PDaddy:这是事实,但括号有助于提高可读性. (11认同)
  • @DisgruntledGoat:他们看起来像是噪音. (7认同)

lep*_*pie 17

侮辱德米特法则:

a.PropertyA.PropertyC.PropertyB.PropertyE.PropertyA = 
     b.PropertyC.PropertyE.PropertyA;
Run Code Online (Sandbox Code Playgroud)


lep*_*pie 17

投掷NullReferenceException:

if (FooLicenceKeyHolder == null)
    throw new NullReferenceException();
Run Code Online (Sandbox Code Playgroud)

  • `ArgumentNullException`? (13认同)
  • 我怀疑ArgumentNullException是这种情况下的方法,因为从代码来看,它似乎不是this.FooLicenseHolder是一个函数的参数(至少不是像一个常规的L​​OOK).也许重新编写代码会使你的(完全有效)点更清晰. (5认同)
  • 是的,这将是正确的扔:) (2认同)
  • 此外,我认为一般反模式会手动抛出*任何*异常,运行时自身会在发生错误时抛出 (2认同)

dmp*_*lla 16

这是真的,我亲眼看到了它.

public object GetNull()
{
     return null;
}
Run Code Online (Sandbox Code Playgroud)

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

这使我的一天.

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

  • 他们一定以为null可能会在未来改变:) (7认同)
  • 也许编码器假设null是一个私有变量; O) (2认同)
  • 好吧,你在函数中封装了nullity的概念:P (2认同)

lep*_*pie 14

int foo = 100;
int bar = int.Parse(foo.ToString());
Run Code Online (Sandbox Code Playgroud)

或者更一般的情况:

object foo = 100;
int bar = int.Parse(foo.ToString());
Run Code Online (Sandbox Code Playgroud)

  • 你是对的,他们真的应该使用TryParse().:P (24认同)
  • 这......什么?为什么?-headdesk-你不可能告诉我有人这样做了吗? (9认同)
  • 我没跟你开玩笑,我看到人们这样做是为了贪婪,这是我有过很多WTF时刻之一. (2认同)

Adr*_*der 12

我在我们的项目中发现了这一点,几乎打破了主席......

DateTime date = new DateTime(DateTime.Today.Year, 
                             DateTime.Today.Month, 
                             DateTime.Today.Day);
Run Code Online (Sandbox Code Playgroud)

  • 实际上,正确的用法是:DateTime date = DateTime.Now.Date; (或Today.Date)如果你省略日期,你也会得到时间. (12认同)
  • 或DateTime日期= DateTime.ToDay; (8认同)
  • 对于记录,正确的用法是:DateTime date = DateTime.Now; (7认同)
  • 我并没有真正看到这个代码的大问题,也许编码器只是不知道Date属性... -1 (6认同)
  • 嗯,正确的用法是Datetime date =`Datetime.Now.Date` (3认同)
  • @Spence:不,正确的是`DateTime.Today`. (3认同)
  • @astander,svinto:真的吗?"今天"??你是认真的吗?为了大声哭泣,骆驼外壳真的开始变得无法控制!这是一个令人毛骨悚然的词.今天. (2认同)

Chr*_*arz 11

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

var ok = Bar();
Run Code Online (Sandbox Code Playgroud)

甚至更好:

var i = AnyThing();
Run Code Online (Sandbox Code Playgroud)

以这种方式使用var毫无意义,也没有任何收获.它只是让代码更难以遵循.

  • 我在这里没有看到反模式,var删除了冗余类型定义,因为Bar()或AnyThing()将始终返回相同的类型.如果您将更改Bar()或AnyThing()的返回类型,例如使用接口而不是实现,您将不需要更改ok和i,如果他们只需要接口,这很好. (27认同)
  • 这很糟糕,因为在不知道Bar()和AnyThing()方法的情况下,您无法立即发现类型.在我看来,可读性比保存一些冗余字符更重要.除此之外,var对于这样的语句非常有用:var i = new MyTypeWithVeryLongName(); 不同之处在于您可以立即识别出类型. (11认同)
  • 我同意 - var最近似乎变得过度使用了. (8认同)
  • var something = new Something()很好.你知道对象的类型.更好的是当var与通用方法相结合以减少重复时(遵循DRY规则). (8认同)
  • 不幸的是,ReSharper似乎喜欢建议任何变量声明应该使用var .. (8认同)
  • 我不明白为什么这会是C#中的反模式,因为它在类型推断语言(Haskell,F#等)和弱类型语言(JavaScript,Python等)甚至***中显然都非常好.你可以这样做的方式. (3认同)
  • 如果不清楚Something()返回什么,我会改写它.var person = FindPersonByAddress(address); 对我来说非常清楚. (3认同)
  • 如果您可以将鼠标悬停在变量上并查看其推断类型,那将是可以忍受的. (2认同)
  • 如果这些是*构造函数*,那就没关系,但它们不是.如果这些类型是明显的(例如`Service.Create(...)`),那么它们也可以是工厂类 (2认同)

ant*_*ony 10

  • @Ed Swangren:通过委托进行的调用比`if`测试要昂贵得多,如果有人*与它挂钩,那么它就变成了一个多播委托,这比通过单播委托的呼叫要昂贵得多.请参阅以下帖子的评论:http://stackoverflow.com/questions/9033/hidden-features-of-c/9282#9282 (2认同)

Bev*_*van 10

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

if (myBooleanVariable == true)
{
    ...
}
Run Code Online (Sandbox Code Playgroud)

或者,甚至更好

if (myBooleanVariable != false)
{
    ...
}
Run Code Online (Sandbox Code Playgroud)

这样的结构通常使用CC++开发,其中一个布尔值的想法只是一个约定(0 ==假的,什么都为true); 在C#或其他具有真正布尔值的语言中,这不是必需的(或可取的).

更新:重新描述最后一段以提高其清晰度.

  • 在C和C++中(我还没有听说过C/C++语言),这不是一个约定,它实际上是错误的.因为"其他一切"都是正确的,所以对于某些定义的真(例如,`1`)执行`if(a == true)`,如果`a`是,例如,`4`,则不会按预期工作.同样,在这两种情况下,`if(myBooleanVar)`和`if(!myBooleanVar)`将是一个更好的替代品. (3认同)

Rob*_*vey 9

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

除非该类是一个简单的数据传输对象.

请参阅下面的评论以供讨论和澄清.

  • 上面的"除非"应该触发一个警钟 - 毕竟这可能不是那么明确吗? (5认同)
  • 简单的DTO使用属性而不是公共变量是否有害?我不会说因为存在自动属性.但是,由于我发现WPF数据绑定不适用于公共字段(与公共属性相反)使我忘记了再次声明没有访问器的公共字段/变量. (2认同)

Bin*_*ony 8

我实际看到过这个.

bool isAvailable = CheckIfAvailable();
if (isAvailable.Equals(true))
{ 
   //Do Something
}
Run Code Online (Sandbox Code Playgroud)

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


Spe*_*nce 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.
Run Code Online (Sandbox Code Playgroud)

  • 那时你让我害怕.这是.Net紧凑框架中的错误,而不是win表单中的错误.弱引用在真正的.net CLR中工作,我也支持这样一个事实,即在释放模式下对null的调用将被优化掉(这是一种处理模式的主要动机,这是一种强制生命周期的方法调用持续至少那个长的对象).但.Net CF绝对是一个有趣的野兽. (2认同)

lep*_*pie 6

私人自动实施的属性:

private Boolean MenuExtended { get; set; }
Run Code Online (Sandbox Code Playgroud)

  • 自动实现的属性可能会在以后使用自定义getter和setter方法转换为完整的属性.您无法轻松地对字段执行此操作. (7认同)
  • 您可以,但不能以二进制兼容的方式...但是,无论如何,它们都是私有的,因此它们将是二进制兼容的,因为字段/属性未公开. (5认同)
  • 二进制兼容性和数据绑定是您可能需要使用公共属性的原因,但这些不适用于此处.属性有几个优点.您可以在访问时放置调试断点.您可以轻松更改其读/写访问级别.例如,它们通常可用于重构,将与默认值配对的空检查迁移到属性本身.鉴于创建自动实现的属性所需的工作量差异很小,我会说,无论属性或字段是更好的默认值,都是一种清洗. (5认同)
  • 例如,某些控件仅反映属性,而不反映字段.例如,PropertyGrid.有时在处理反射时需要使用属性,即使这些属性是私有的. (3认同)
  • @ed:祝你好运绑定私有财产! (3认同)

Chr*_*arz 6

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

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

    // Code
}
Run Code Online (Sandbox Code Playgroud)

  • 这不是一个主观意见而不是C#反模式吗? (12认同)
  • 这就是我在大学里被教导编码的方法;)不要再这样做了,这是一种痛苦. (3认同)
  • 这有什么问题?如果你正确编码你的方法,它们足够短,无论如何都能看到你的所有变量.我认为应该在块的顶部而不是方法中定义变量,除非它们必须用于范围问题. (3认同)

Bin*_*ony 6

两个字符串反模式
Anti-Pattern#1
检查字符串是否为null或为空

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

//Good
string.IsNullOrEmpty(myString)
Run Code Online (Sandbox Code Playgroud)

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

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

//Good
string.IsNullOrWhiteSpace(myString) 
Run Code Online (Sandbox Code Playgroud)


lep*_*pie 5

不用铸造(请相信编译器):

foreach (UserControl view in workspace.SmartParts)
{
  UserControl userControl = (UserControl)view;
  views.Add(userControl);
}
Run Code Online (Sandbox Code Playgroud)

  • @ed:它没有添加到自身.`views`!=`view`.;) (2认同)

Bin*_*ony 5

if(data != null)
{
  variable = data;
}
else
{
  variable = new Data();
}
Run Code Online (Sandbox Code Playgroud)

可以写得更好

variable = (data != null) ? data : new Data();
Run Code Online (Sandbox Code Playgroud)

甚至写得更好

variable = data ?? new Data();
Run Code Online (Sandbox Code Playgroud)

最后的代码清单适用于.NET 2.0及更高版本