只是,那并不表明 TryParse
方法更好。某些意况下适合,某些景况下则不吻合。那就是为何有三种办法供我们挑选了。依据你的具体景况采取适当的点子,并切记,作为一个开发者,非常是一心可以变成您的爱人的。

此外,尽管你知道要对方法2的重临值进行判定,即使您发觉值为空,接下去你会如何做?在这几个点子中报告错误合适吧?如果类型转换失利了你还有其余的法门去品味吧?即使没有的话,那么抛出那几个这些是绝无仅有正确的挑三拣四,并且丰盛的抛出点离其爆发点越近越好。


一些C#的程序员甚至都不清楚LINQ的留存,好在不清楚的人正在渐渐缩减。但是还有些人误以为LINQ只用在数据库询问中,因为LINQ的重点字和SQL语句实在是太像了。

关于C#

(别的需求指出的是,定义增加方法的IEnumerable接口和Enumerable类的名字间的相似性没什么奇怪的。那种相似性只是随意的风格拔取。)

如上所示,在C#中,struct关键字是用来定义一个值类型,而class关键字是用来定义引用类型的。
对于这多少个有C++编程背景人来说,如果被C++和C#里头某些类似的重点字搞混,恐怕会对以上那种表现感到很受惊。

下边的例证演示了其余一组广泛的艺术,一种会抛出非常,而另一种则不会:

率先个Equals方法(没有comparisonType那参数)和利用==操作符的结果是如出一辙的,但便宜是,它显式的指明了比较类型。它会按顺序逐字节的去比较字符串。在诸多气象下,那正是你所希望的比较类型,尤其是当相比较一些由此编程设置的字符串,像文件名,环境变量,属性等。在那么些景况下,只要按梯次逐字节的可比就足以了。使用不带comparisonType参数的Equals方法进行比较的绝无仅有糟糕的地点在于那一个读你程序代码的人只怕不了然你的相比类型是怎么着。

能源败露大概在具有的环境中都会掀起关怀。不过,C#提供了一种健康的体制使财富的使用变得简单。假诺创造使用,可以大大收缩走漏出现的机率。NET
framework定义了一个IDisposable接口,仅由一个Dispose()构成。任何完结IDisposable的接口的对象都会在对象生命周期截止调用Dispose()方法。调用结果肯定而且决定性的放飞占用的能源。

答案是,当在LINQ语句中的基础对象都引用到SQL表中的数据(如与在这一个事例中,在实体框架为DbSet的靶子的图景下),该语句被转换成一个T-SQL语句。然后根据的T-SQL的平整,而不是C#的平整,所以在上述情状下的相比较截止是不区分轻重缓急写的。

对此拍卖抽象操纵集合职责,LINQ无疑是宏大的。无论他们是在内存的靶子,数据库表,恐怕XML文档。在那样一个周到世界中间,你不需要领悟底层对象。可是一旦我们生活在一个到家世界中间大概会带来错误。事实上,当在规范的一样数量上进行时,即便该数量碰巧在一个不比的格式之中相同的,LINQ语句能回来不一致的结果

  if (int.TryParse(myString, out myInt)) 
  {
      // use myInt
  }
  else 
  {    
      // use default value
  }

C#是种面向对象的强类型语言。C#在编译和运作时都有些强类型检查,使在大部顶级的编程错误可以被尽早地觉察,而且地点固定一定精准。比较于那多少个不拘泥类型,在不合规操作很久后才报出可追踪到莫明其妙错误的语言,那足以为程序员节省见惯不惊时刻。然则,许多程序员有意或下意识地放弃了那个检测的有点,那导致本文中探究的有的标题。

public bool Equals(string value);  



public bool Equals(string value, StringComparison comparisonType);

定义在System.Linq.Enumerable类中的static方法(叫做“extension method”)

在C#中,值得类型无法为空。依据定义,值的连串值,甚至伊始化变量的值类型必须有一个值。那就是所谓的该品种的专擅认同值。这一般会促成以下,意想不到的结果时,检查一个变量是或不是未开首化:

骨子里大家大概早就这么落成了那一个方法,而不是问怎么要有伸张方法。扩大方法自己只是C#的一个惠及你无需后续、重新编译可能涂改原始代码就可以给已存的在品种“添加”方法的法子。

来源:http://www.oschina.net/translate/top-10-mistakes-that-c-sharp-programmers-make

设想一下,该对象之一的账号会时有发生什么样。状态万分“Active”(注意大写A)?

本文描述了10个 C# 程序员常犯的不当,或相应防止的牢笼。

  Point point1 = new Point(20, 30);
  Point point2 = point1;
  point2.X = 50;
  Console.WriteLine(point1.X);       // 20 (does this surprise you?)
  Console.WriteLine(point2.X);       // 50

  Pen pen1 = new Pen(Color.Black);
  Pen pen2 = pen1;
  pen2.Color = Color.Blue;
  Console.WriteLine(pen1.Color);     // Blue (or does this surprise you?)
  Console.WriteLine(pen2.Color);     // Blue

很显眼,倘若不对方法2再次回到的结果开展判定的话,最后很或许会发出一个
NullReferenceException
的尤其,那只怕会冒出在稍晚些的时候,那使得难题更难追踪。相比较的话,方法1会即时抛出一个
InvalidCastExceptionmaking,那样,难点的源于就很明显了。

有关本文

等一会,在我们前面商量过的字符串比较中, 大家看见 ==
操作符扮演的角色就是简约的可比. 所以,为什么在这几个规则下, ==
表现出的是其余的一个花样呢 ?

固然您想要敬爱的行事会因值类型和引用类型而异,举例来说,假设您想把一个目标作为参数传给一个艺术,并在这些艺术中修改那个目的的气象。你早晚要力保您在拍卖正确的类型对象。

拔取伸张方法真的有优势,但也会让那多少个对它不打听如故认识不正确的开发者胃疼,浪费时间。特别是在看在线示例代码,或然其余已经写好的代码的时候。当那几个代码爆发编译错误(因为它调用了这么些鲜明没在被调用类型中定义的方法),一般的同情是考虑代码是不是采取于所引用类库的别样版本,甚至是不相同的类库。很多时刻会被花在找新本子,大概被认为“丢失”的类库上。

  class Program {
      static Point point1;      static Pen pen1;      static void Main(string[] args) {
          Console.WriteLine(pen1 == null);      // True
          Console.WriteLine(point1 == null);    // False (huh?)
      }
  }

就算有多如牛毛程序员使用==操作符来相比较字符串,不过那种办法其实是最不推荐使用的。首要原因是出于那种艺术没有在代码中显式地指定使用哪序列型去比较字符串。
相反,在C#中判断字符串是或不是等于最好使用Equals方法:

  public struct Point { … }     // defines a “value” type
  public class Pen { … }        // defines a “reference” type

熟悉C#的片段重点的一线之处,像本文中所提到的那多少个(但不压制这些),可以扶持大家更好的去接纳语言,从而幸免有些周边的骗局。

对C#编译器来说,伸张方法是个“语法糖”,使大家能把代码写得更清楚,更易于维护(多数情景下)。分明,前提是您领悟它的用法,否则,它会相比较不难令人迷惑,特别是一初叶。

#5常见错误:在LINQ语句之中没有设想底层对象

常见错误 #3: 使用不适当或未指定的办法相比字符串

一个宽广的事例是,你改改了您的代码,并移除了对一些变量的施用,但是,你忘了移除该变量的宣示。程序可以很好的运作,可是编译器会指示有未利用的变量。程序可以很好的周转使得一些程序员不去修补警告。更有甚者,有些程序员很好的使用了Visual
Studio中“错误列表”窗口的隐藏警告的功效,很简单的就把警告过滤了,以便专注于错误。不用多久,就会积累一堆警告,那些警告都被“惬意”的粗心了(更糟的是,隐藏掉了)。


铭记,如若您仔细看的话,你会发现,C#编译器给了您多多关于你程序健壮性的实用的音信。不要忽略警告。你只需花几秒钟的时刻就足以修复它们,当出现的时候就去修补它,那足以为您节省不胜枚举年华。试着为温馨作育一种“洁癖”,让Visual
Studio 的“错误窗口”一贯突显“0错误,
0警告”,一旦出现警示就感觉不舒服,然后随即把警告修复掉。


C#在运营时也会强制进行项目检查。相对于像C++那样会给错误的类型转换赋一个随机值的语言来说,C#那足以使您更快的找到出错的职位。不过,程序员再五次无视了C#的这一特色。由于C#提供了两种类型检查的法门,一种会抛出分外,而另一种则不会,那很只怕会使她们掉进这么些“坑”里。有些程序员倾向于回避相当,并且认为不写
try/catch 语句可以节约一些代码。

假如您不知道您正在接纳的对象是还是不是是值类型或引用类型,你恐怕会遇上有的惊喜。例如:

您借使这么写:

C#是一门强大的同时很利索的言语,它有许多机制和言语专业来明确的坚实你的生产力。和别的语言一样,假使对它能力的摸底有限,那很只怕会给您带来阻碍,而不是好处。正如一句谚语所说的那样“knowing
enough to be
dangerous”(译者注:意思是自以为已经精通丰裕了,可以做某事了,但骨子里不是)。

理所当然了,任何规则都有不一样。所以,有些时候,就算你的代码在编译器看来是不怎么难题的,但是那正是你想要的。在那种很少见的情景下,你最好应用
#pragma warning disable [warning id]
把吸引警告的代码包裹起来,而且只包裹警告ID对应的代码。那会且只会抑制对应的警戒,所以当有新的告诫发生的时候,你如故会知晓的。.
总结

为何不是【point
1】空?答案是,点是一个值类型,和默许值点(0,0)一样,没有空值。
那是一个非凡简单和宽广的荒唐。在C#中过多(不过不是全方位)值类型有一个【IsEmpty】属性,你可以看看它是还是不是等于私自认同值:

增加方法通过在文件先导添加using
[namespace];引入到功用域。你须要了然您要找的扩展方法所在的名字空间。即使你领悟您要找的是何许,那一点很简单。

在上头的代码中,myAccounts参数的花色被声称为IEnumerable<Account>,myAccounts引用了一个Sum
方法 (C# 使用类似的 “dot notation”
引用方法如故接口中的类),大家希望在IEnumerable接口中定义一个Sum()方法。但是,IEnumerable没有为Sum方法提供任何引用并且只有如下所示的凝练定义:

一般景况下,即便LINQ是一个有益于的和相同的方法来查询对象的集合,在具体中您还须要知道您的话语是还是不是会被翻译成什么,来确保您的代码的一言一动将如预期运营。

decimal total=(from accout in myaccouts
    where accout.status=='active'
    select accout.Balance).sum();

在增加方法的名字和类中定义的艺术的名字如出一辙,只是在点子签名上有微小区其他时候,甚至那一个熟练扩充方法的开发者也偶尔犯上面的一无所能。很多岁月会被花在查找“不存在”的拼写错误上。

 namespace System.Linq 
 {
    public static class Enumerable 
    {      ...
      // the reference here to “this IEnumerable<TSource> source” is
      // the magic sauce that provides access to the extension method Sum
      public static decimal Sum<TSource>(this IEnumerable<TSource> source,Func<TSource, decimal> selector);      ...
    }
 }

如同先前涉及的,LINQ状态珍重于IEnumerable接口的落成目标,比如,上边的简易函数会研商帐户集合中的帐户余额:

大规模错误#8:遗漏能源自由

运用带comparisonType的Equals方法去相比较字符串,不仅会使您的代码更明显,还会使你去考虑清楚要用哪一类档次去相比较字符串。那种艺术非凡值得你去行使,因为即使在韩语中,按梯次进行的相比和按语言区域展开的可比之间并不曾太多的界别,可是在其余的片段语种恐怕会有很大的不等。假使您忽视了那种只怕,无疑是为你协调在以往的征途上挖了许多“坑”。举例来说:

普遍的荒唐#2:误会未初阶化变量的暗中同意值

  int.Parse();     // 如果参数无法解析会抛出异常
  int.TryParse();  // 返回bool值表示解析是否成功

  IEnumerable.First();           // 如果序列为空,则抛出异常
  IEnumerable.FirstOrDefault();  // 如果序列为空则返回 null 或默认值

而不是如此:

上边是有的为主的点拨原则:


  // 方法 1:
  // 如果 account 不能转换成 SavingAccount 会抛出异常
  SavingsAccount savingsAccount = (SavingsAccount)account;

  // 方法 2:
  // 如果不能转换,则不会抛出异常,相反,它会返回 null
  SavingsAccount savingsAccount = account as SavingsAccount;

在C#
3.0中,LINQ的引入改变了大家过去对聚集对象的询问和改动操作。从那将来,你应当用LINQ去操作集合,而不是透过迭代的方法。

最安全的执行是延续为Equals方法提供一个comparisonType的参数。

C#提供了大批量的集结类型的对象,上面只列出了里面的一局地:

  using (FileStream myFile = File.OpenRead("foo.txt")) {
    myFile.Read(buffer, 0, 100);
  }

警告的出现是有缘由的。所有C#的编译错误都注解你的代码有缺点,同样,一些告诫也是那般。那两者之间的界别在于,对于警告的话,编译器可以遵从你代码的提醒工作,不过,编译器发现你的代码有一点小标题,很有恐怕会使你的代码不可以根据你的料想运维。

答案是Sum并不在IEnumerable接口内定义,而是一个


周边错误 #9: 回避相当

扩充方法的明显特点是率先个形参前的this修饰符。那就是编译器知道它是一个恢弘方法的“奥妙”。它所修饰的参数的类型(那个例子中的IEnumerable)表明那几个类依旧接口将显示已毕了那些办法。

  • 当比较用户输入的字符串或然将字符串比较结实显示给用户时,使用本地化的可比(CurrentCulture
    或者CurrentCultureIgnoreCase)。
  • 当用于程序设计的比较字符串时,使用原有的可比(Ordinal 或然OrdinalIgnoreCase)
  • InvariantCulture和InvariantCultureIgnoreCase一般并不接纳,除非在受限的境地之下,因为本来的相比一般功用更高。若是与本土文化有关的比较是需求的,它应该被实施成基于当下的文化大概另一种特殊文化的比较。

在C#中,用伸张方法变得特别流行。除了LINQ,在别的七个来自微软明天被大面积采纳的类库Unity
Application Block和Web API
framework中,也使用了扩充方法,而且还有许多任何的。框架越新,用伸张方法的只怕越大。

Console.WriteLine(point1.IsEmpty);        // True

C++
和别的许多语言的程序员,习惯了给变量赋值的时候,要么赋单纯的值,要么是存活对象的引用。不过,在C#
中,是值依然引用,是由写那个目的的程序员决定的,而不是实例化对象并赋值的程序员决定的。那往往会坑到
C# 的新手程序员。

而是Sum方法应该定义到什么地方?C#是强类型的言语,因而只要Sum方法的引用是行不通的,C#编译器会对其报错。我们清楚它必须存在,但是相应在哪里啊?其它,LINQ提供的供查询和集合结果具有办法在何地定义呢?

其它,对Equals
方法来说,字符串也不乏先例提供了Compare方法,能够提供字符串的对峙顺序音信而不仅测试是或不是等于。这些主意可以很好适用于<,
<=, >和>= 运算符,对上述议论同样适用。

即便所有C#的类中都定义了析构方法,不过销毁对象(C#中也称为终结器)可能存在的标题是你不确定它们在时候被调用。他们在今后一个不确定的年华被垃圾回收器调用(一个异步的线程,此举恐怕引发额外的产出)。试图幸免那种由垃圾回收器中GC.Collect()方法所施加的强制限制并非一种好的编程实践,因为恐怕在垃圾回收线程试图回收适宜回收的靶酉时,在不足预见的时刻内导致线程阻塞。

知晓了那一点,我们得以看到地点介绍的sumAccounts方法能以下边的艺术完毕:

另一个周边的牢笼是团结去落实一个聚集类型。那并不是说永远不要这么做,你可以由此接纳或扩大.NET提供的部分被普遍利用的集结类型来节省大批量的年华,而不是去重新造轮子。
越发是,C#的C5 Generic Collection Library
和CLI提供了无数万分的聚合类型,像持久化树形数据结构,基于堆的优先级队列,哈希索引的数组列表,链表等以及越多。

在地点示例中使用using语句,你就可以规定myFile.Dispose()方法会在文书使用完之后被立即调用,不管Read()方法有没有抛分外。

理所当然,你也得以写你协调的壮大方法。但是必须意识到即使伸张方法看起来和任何实例方法同样被调用,但那实际上只是幻觉。事实上,伸张方法无法访问所伸张类的民用和保养成员,所以它不或者被看做传统三番两回的替代品。

  decimal total = (from account in myAccounts
               where account.Status == "active"
               select account.Balance).Sum();

那并代表最好不要用终结器,显式释放资源并不会导致其中的其他一个结果。当您打开一个文件、网络端口可能数额连接时,当你不再拔取那一个财富时,你应有尽早的显式释放那几个能源。

科普错误 #10: 累积编译器警告而不处理

public decimal SumAccounts(IEnumerable<Account> myAccounts) 
{      
   return myAccounts.Sum(a => a.Balance);
}

在C#中有那些办法来相比字符串。

 public interface IEnumerable<out T> : IEnumerable 
 {
      IEnumerator<T> GetEnumerator();
 }

只是在稍微景况下,有太多的选项和没有丰富的选料一样不佳,集合类型也是那般。数量众多的挑选余地肯定可以保险是你的干活健康运作。然而你最好如故花一些日子提前查找并问询一下集结类型,以便采纳一个最契合你需求的集纳类型。那最后会使您的顺序质量更好,裁减失误的只怕。

C#是达标微软公共语言运转库(CL福特Explorer)的个别语言中的一种。完毕CLLAND的言语可以受益于其带来的特征,如跨语言集成、万分处理、安全性增强、部件组合的简易模型以及调节和分析服务。作为当代的CLENVISION语言,C#是行使最为广泛的,其采用场景针对Windows桌面、移出手机以及服务器环境等繁杂、专业的开支品种。

再增加拔取了编辑器的智能感知的效益,那种不当就很有或然发生。


本条荒唐并不是C#所特有的,但是在C#中那种情景却比较多,特别是从C#编译器弃用了从严的门类检查之后。

科普错误 #1: 把引用当做值来用,只怕反过来

如你所见,即使Point和Pen对象的创立形式相同,不过当一个新的X的坐标值被分配到point2时,
point1的值保持不变
。而当一个新的color值被分配到pen2,pen1也跟着更改。由此,大家可以推论point1和point2各种都富含本身的Point对象的副本,而pen1和pen2引用了同一个Pen对象
。假若没有那么些测试,大家怎么可以精通那些原理?

decimal total = 0;  
foreach (Account account in myAccounts) 
{    
     if (account.Status == "active") 
     {
        total += account.Balance;
     }
}

如若有一个成团指定的成分类型(如string或bit)和您正在操作的一模一样,你最好优先挑选使用它。当指定相应的成分类型时,那种集合的频率更高。


为了利用好C#中的类型安全,你最好采取选择一个泛型接口,而不是运用非泛型的借口。泛型接口中的成分类型是您在在申明对象时指定的类型,而非泛型中的成分是object类型。当使用一个非泛型的接口时,C#的编译器无法对你的代码进行项目检查。同样,当您在操作原生类型的联谊时,使用非泛型的接口会导致C#对那几个连串进行频繁的装箱(boxing)和拆箱(unboxing)操作。和利用指定了恰当类型的泛型集合相比,那会带来很驾驭的性子影响。

一种方法是去看一下目的是怎么样定义的(在Visual
Studio中,你可以把光标放在对象的名字上,并按下F12键)

比方在一个代码段中制造并释放一个对象,却忘记调用Dispose()方法,那是不足原谅的,因而C#提供了using语句以保障无论代码以什么样的办法退出,Dispose()方法都会被调用(不管是万分,return语句,恐怕简单的代码段截至)。那么些using和事先提到的在文书开端用来引入名字空间的一律。它有其余一个众多C#开发者都未曾发觉的,完全不相干的目标,约等于确保代码退出时,对象的Dispose()方法被调用:

譬如,上边演示了C#中开展显示类型转换的三种不一致的艺术:

  public decimal SumAccounts(IEnumerable<Account> myAccounts) 
  {
      return Enumerable.Sum(myAccounts, a => a.Balance);
  }

CLEscort托管环境扮演了垃圾回收器的剧中人物,所以您不须求显式释放已创造对象所占据的内存。事实上,你也不可以显式释放。C#中平素不与C++
delete对应的运算符恐怕与C语言中free()函数对应的法子。但那并不表示你可以忽略所有的利用过的目标。许多对象类型封装了很多任何类型的系统能源(例如,磁盘文件,数据连接,互连网端口等等)。保持这几个财富利用状态会猛烈耗尽系统的财富,削弱质量并且最后造成程序出错。

Array,ArrayList,BitArray,BitVector32,Dictionary<K,V>,HashTable,HybridDictionary,List<T>,NameValueCollection,OrderedDictionary,Queue, Queue<T>,SortedList,Stack, Stack<T>,StringCollection,StringDictionary.

广泛错误 #7: 对手头上的义务选取不当的集聚类型

固然本文探讨的多数错误是针对 C# 的,有些错误与任何以 CL索罗德为对象的语言,大概使用了 Framework Class Library (FCL) 的言语也有关。

好吧,假设myaccout是Dbset的目标。(暗中同意设置了不一样组别轻重缓急写的布署),where表明式仍会同盟该因素。但是,若是myaccout是在内存阵列之中,那么它将不合作,因而将时有暴发不相同的总的结果。

当C#编译器遇到一个目的的实例调用了一个艺术,并且它在那些目标的类中找不到非凡形式,它就会尝试在功用域中所有的扩张方法里找一个匹配所须要的类和办法签名的。要是找到了,它就把实例的引用当做第二个参数传给这多少个增加方法,然后尽管有其他参数的话,再把它们依次传入增添方法。(要是C#编译器没有在效能域中找到相应的恢弘方法,它会抛措。)

多少程序员认为“万分有害”,所以她们任其自然的以为不抛出十分的先后显得特别“高大上”。固然在一些情况下,这种观点是不利的,但是那种理念并不适用于所有的意况。

  string s = "strasse";

  // outputs False:
  Console.WriteLine(s == "stra&szlig;e");
  Console.WriteLine(s.Equals("stra&szlig;e"));
  Console.WriteLine(s.Equals("stra&szlig;e", StringComparison.Ordinal));
  Console.WriteLine(s.Equals("Stra&szlig;e", StringComparison.CurrentCulture));        
  Console.WriteLine(s.Equals("stra&szlig;e", StringComparison.OrdinalIgnoreCase));

  // outputs True:
  Console.WriteLine(s.Equals("stra&szlig;e", StringComparison.CurrentCulture));
  Console.WriteLine(s.Equals("Stra&szlig;e", StringComparison.CurrentCultureIgnoreCase));

大规模误区 #4: 使用迭代式 (而不是申明式)的语句去操作集合

然则,倘使您不经意掉这一类的警戒,类似于上面这一个事例迟早会合世在您的代码中。

  class Account 
  {

      int myId;      
      int Id;   // 编译器已经警告过了,但是你不听

      // Constructor
      {          
         this.myId = Id;     // OOPS!
      }

  }
  try 
  {
    myInt = int.Parse(myString);    // use myInt
  }
  catch (FormatException) 
    // use default value
  }

举个实际的事例,某些意况下当万分爆发时,你有另一个可选的办法(如,暗中认同值),那么,采取不抛出万分的点子是一个相比好的选项。在这种处境下,你最接近下边那样写:


即使这是一个很简短的例子,在有点情状下,一个十足的LINQ语句可以任意地更迭掉你代码中一个迭代轮回(或嵌套循环)里的几十条语句。更少的代码日常意味着爆发Bug的机遇也会更少地被引入。但是,记住,在性质方面大概要衡量一下。在品质很紧要的光景,尤其是你的迭代代码可以对您的集纳进行假若时,LINQ做不到,所以肯定要在这两种格局之间比较一下质量。

诸如,请考虑上边的讲话:

今后,你的代码中有了一个严重的不当(可是编译器只是出口了一个警示,其缘由现已说明过),那会浪费你大量的光阴去追寻那错误,具体意况由你的程序复杂程度决定。如果你一初步就注意到了那个警示,你只要求5分钟就可以修改掉,从而幸免这几个难题。

广大错误 #6:对扩张方法感到思疑大概被它的款式诈骗

纵然数据库的查询操作是LINQ的一个百般出众的应用,不过它同样能够利用于各样可枚举的集合对象。(如:任何已毕了IEnumerable接口的靶子)。举例来说,假诺您有一个Account类型的数组,不要写成上边那样:

相关文章

网站地图xml地图