C#的隐藏特性是什么?

1473

在我从这个问题中学到以下知识后,这个想法浮现在我的脑海中:

where T : struct

我们这些C#开发者都知道C#的基础,比如声明、条件语句、循环、运算符等等。
有些人甚至掌握了泛型, 匿名类型, Lambda表达式, LINQ等高级用法。
但是C#还有哪些隐藏的特性或技巧,即使是C#的粉丝、狂热者、专家也很少知道呢?
以下是目前已经揭示出来的特性:


关键词

属性

语法

  • ?? (合并空值) 操作符由 kokos 实现
  • 数字标记由 Nick Berardi 实现
  • where T:newLars Mæhlum 实现
  • 隐式泛型由 Keith 实现
  • 单参数 lambda 表达式由 Keith 实现
  • 自动属性由 Keith 实现
  • 命名空间别名由 Keith 实现
  • 使用 @ 的逐字字符串字面量由 Patrick 实现
  • enum 值由 lfoust 实现
  • @variablenames 由 marxidad 实现
  • event 操作符由 marxidad 实现
  • 格式化字符串括号由 Portman 实现
  • 属性访问器可访问性修饰符由 xanadont 实现
  • 条件 (三元) 操作符 (?:) 由 JasonS 实现
  • checkedunchecked 操作符由 Binoj Antony 实现
  • implicitexplicit 操作符由 Flory 实现

语言特性

Visual Studio 特性

框架

方法和属性

  • String.IsNullOrEmpty()方法由KiwiBastard提供
  • List.ForEach()方法由KiwiBastard提供
  • BeginInvoke()EndInvoke()方法由Will Dean提供
  • Nullable<T>.HasValueNullable<T>.Value属性由Rismo提供
  • GetValueOrDefault方法由John Sheehan提供

提示与技巧

  • 通过Andreas H.R. Nilsson提供的良好方法处理事件处理程序
  • John提供的大写字母比较
  • 无需反射即可访问匿名类型,由dp提供
  • Will提供的快速懒惰实例化集合属性的方法
  • roosteronacid提供的类似JavaScript的匿名内联函数

其他

296个回答

65

条件字符串格式化:

根据数字是正数、负数或零,应用不同的格式。

string s = string.Format("{0:positive;negative;zero}", i);

例如

string format = "000;-#;(0)";

string pos = 1.ToString(format);     // 001
string neg = (-1).ToString(format);  // -1
string zer = 0.ToString(format);     // (0)

2
这类似于正则表达式,非常有用,但我也记不住它们。我使用padleft和padright处理上述内容。 - tuinstoel
酷,我从来不知道这是可能的... 有没有任何文档记录? - Thomas Levesque
@Thomas:在MSDN的“分号(;)分隔符”部分中有详细记录,该部分位于自定义数字格式化主题的末尾。链接地址为:http://msdn.microsoft.com/zh-cn/library/0c899ak8.aspx - devstuff

64

事件实际上是代理对象,在内部可以将多个函数连接到它并使用 += 和 -= 运算符分别分离它们。

事件还可以通过添加/删除进行控制,类似于 get/set,只是当使用 += 和 -= 时会被调用:

public event EventHandler SelectiveEvent(object sender, EventArgs args) 
  { add 
     { if (value.Target == null) throw new Exception("No static handlers!");
       _SelectiveEvent += value;
     }
    remove
     { _SelectiveEvent -= value;
     }
  } EventHandler _SelectiveEvent;

61

不要忘记使用goto语句。


55
不,我们忘了它吧。 ;) - Gary Willoughby
3
不,让我们滥用它直到末日。 ;) - chakrit
11
如何在不使用布尔变量或将整个代码块移至函数或lambda的情况下,跳出多层循环?语言中一定存在这样做的原因... - Calmarius
1
在嵌套循环中,深度为两到三层,这是绝对的救星。虽然我想不出其他可能合法使用它的原因。 - tomfanning
1
@tomfanning - 在switch语句中,需要考虑继续执行下一个case的情况,这时候可以用goto语句来实现。 - Fraser
显示剩余5条评论

56

更多的是一个运行时特性,但我最近了解到有两个垃圾收集器。工作站垃圾回收器和服务器垃圾回收器。工作站垃圾回收器是Windows客户端版本的默认设置,但服务器垃圾回收器在多核机器上运行速度更快。


<configuration>
   <runtime>
      <gcServer enabled="true"/>
   </runtime>
</configuration>

小心,服务器GC需要更多的内存。


不错的提示。你应该将这个问题移动到隐藏的.NET基类库问题中http://stackoverflow.com/questions/122784/hidden-net-base-class-library-classes - John Sheehan
太棒了。我有一个多核心的Web服务器;它的额外核心和内存一直被浪费! - tsilb
这个优化在 IronScheme 上对我也很有效 :) - leppie
3
在 Windows 的服务器版本(如 Server 2003)中,默认使用服务器 GC。而在客户端版本,如 Vista,则默认使用工作站 GC。 - dso

55

在我往上看的时候,我没有看到这个 - 直到最近我才意识到可以从一个构造函数中调用另一个构造函数:

class Example
{
    public Example(int value1)
        : this(value1, "Default Value")
    {
    }

    public Example(int value1, string value2)
    {
        m_Value1 = value1;
        m_value2 = value2;
    }

    int m_Value1;
    string m_value2;
}

1
虽然我在不同的类之间使用了这个东西,但从未考虑在同一个类中使用它。 我已经到处寻找像这样的东西了!太棒了! - Boris Callens
你们能否提供一个展示如何在交叉类和基类中使用的示例链接吗? - Maslow
3
我认为你的意思是:公共示例(int value1) :此(value1,“默认值”) { } - rball
1
太敏锐了rball!1年,21个赞,竟然没有人发现我的故意错误;)已经修复。 - Grokys
当您继承基类时,也可以使用类似的技术。类似用法为:": base(value1, "默认值")"。 - J. Mitchell
显示剩余3条评论

55

其他不常用的操作符包括checkedunchecked

short x = 32767;   // 32767 is the max value for short
short y = 32767;
int z1 =  checked((short)(x + y));   //will throw an OverflowException
int z2 =  unchecked((short)(x + y)); // will return -2
int z3 =  (short)(x + y);            // will return -2

6
要是用 short.MaxValue 代替 32767 并注释会更好,你觉得呢? - Clinton Pierce
25
提醒大家确切的最大值是多少! - Binoj Antony
也许我们应该将“32767”列为short的最大值,作为它本身的隐藏语言特性?(我认为硬编码数字是程序员的隐含伦理) - sehe

55

使用"throw;"而不是"throw ex;"来保留堆栈跟踪

如果重新抛出异常时没有添加额外的信息,请使用"throw"而不是"throw ex"。在catch块中使用一个空的"throw"语句将发出特定的IL代码,以重新抛出异常并保留原始的堆栈跟踪。"throw ex"会丢失与异常原始来源相关的堆栈跟踪。


48

我只想复制那段没有注释的代码。所以,诀窍就是简单地按下Alt键,然后选择您喜欢的矩形区域(例如下面)。

protected void GridView1_RowCommand(object sender, GridViewCommandEventArgs e)
    {
        //if (e.CommandName == "sel")
        //{
        //    lblCat.Text = e.CommandArgument.ToString();
        //}
    }
在上面的代码中,如果我想选择:
e.CommandName == "sel"

lblCat.Text = e.Comman

然后我按住Alt键,选择矩形,无需取消注释。

看这个。


2
有趣的Visual Studio功能,但问题是关于C#。 - Fernando
11
在这个问题中有一个名为“Visual Studio Features”的部分,你的答案完美适合在那里。 - Roman Boiko
4
这不仅限于 Visual Studio 功能,你也可以在 Microsoft Word、Notepad2 等软件中完成这个操作。 - chakrit
13
在VS2010中,你不仅可以选择文本,还可以通过此方法编辑文本 - 例如,只需在每行前面使用alt键选择空格并开始输入单词“private”,就可以一次性地为多个字段声明添加该单词,从而更正了疏忽掉落该单词的不良做法。 - Matt DeKrey
1
在许多文本编辑器中,这被称为垂直选择。 - Singlet
显示剩余2条评论

48

我发现了一些隐藏的功能:

  • stackalloc可以让你在堆栈上分配数组。
  • 匿名方法没有显式参数列表,但可以隐式转换为具有非out/ref参数的任何委托类型(对于事件非常方便,如早期评论中所述)。
  • 很多人并不清楚什么是事件(像属性的get/set一样都是成对的方法add/remove)。C#中类似字段的事件声明了一个变量和一个事件。
  • ==!=运算符可以重载成返回除bool以外的类型。这很奇怪,但是确实如此。
  • C# 3中的查询表达式翻译在某些方面真的很“简单”,这意味着您可以让它做一些非常奇怪的事情
  • 可空类型具有特殊的箱化行为:null值被封装为null引用,您还可以从空引用解包到可为空类型。

1
不幸的是,stackalloc 需要在不安全的上下文中使用。 - RickNZ

46

@David在达科他:

Console.WriteLine( "-".PadRight( 21, '-' ) );

我曾经这样做,直到我发现String类有一个构造函数,可以以更简洁的方式完成同样的事情:

new String('-',22);

为什么不这样做 Console.WriteLine( "".PadRight( 22, '-' ) ); - Jimmy
为了实现更短、更简洁的代码,例如。 - Konamiman

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接