C#隐藏的function?

我从这个问题中得知以下内容后,

where T : struct 

我们,C#开发人员,都知道C#的基础知识。 我的意思是声明,条件,循环,运营商等

我们有些人甚至掌握了像generics , 匿名types , lambda , LINQ ,…

但是C#中最隐藏的特性或者技巧是甚至连C#粉丝,上瘾者,专家都不知道的?

以下是迄今为止显示的function:

关键词

  • Michael Stum的 yield
  • var由迈克尔Stum
  • using() kokos的 using()语句
  • readonly由kokos
  • as Mike Stone一样
  • as /由Ed Swangren
  • (由Rocketpants改进)
  • 由死亡者 default
  • global::由pzycoman
  • using()由AlexCuse块
  • 由JakubŠturc volatile
  • extern alias由JakubŠturc

属性

  • 由Michael Stum创build的 DefaultValueAttribute
  • ObsoleteAttribute DannySmurf的属性
  • DebuggerDisplayAttribute
  • DebuggerBrowsableDebuggerStepThrough by bdukes
  • ThreadStaticAttribute由marxidad
  • FlagsAttribute由Martin Clarke
  • 由AndrewBurns提供的 ConditionalAttribute 属性

句法

  • ?? (合并nulls )运营商kokos
  • 号码由尼克·贝拉尔迪旗帜
  • where T:new的拉尔斯Mæhlum
  • Keith的隐式generics
  • Keith的单参数lambdas
  • 汽车属性由基思
  • Keith的命名空间别名
  • Patrick用@逐字string文字
  • enum值由lfoust
  • 由marxidad @variablenames
  • 由marxidad event操作员
  • 格式化string括号由波特曼
  • xanadont的属性访问器可访问性修饰符
  • 由JasonS提供的条件(三元)运算符( ?: :)
  • 经Binoj Antony checkedunchecked操作员
  • implicit and explicit操作符Flory

语言function

  • 可空的types由布拉德·巴克
  • Keith的匿名types
  • Judah Himango的 __makeref __reftype __refvalue __refvalue
  • 由lomaxx的对象初始值设定项
  • 格式string由David在达科他州
  • 扩展方法由marxidad
  • Jon Erickson的 partial方法
  • John Asbeck的预处理指令
  • Robert Durgin的 DEBUG预处理器指令
  • 运营商由SefBkn重载
  • 键入由chakrit推断
  • 布尔运算符由Rob Gough 带到下一个层次
  • 通过价值型variables作为接口没有罗马Boiko拳击
  • 以编程方式确定由Roman Boiko声明的variablestypes
  • Chris的静态构造函数
  • 使用LINQ by roosteronacid更容易在眼睛/浓缩的ORM映射
  • __arglist Zac保龄球

Visual Studiofunction

  • 在Himadri编辑器中select文本块
  • DannySmurf的片段

骨架

  • KiwiBastard的 TransactionScope
  • KiwiBastard的 DependantTransaction 交易
  • IainMH的 Nullable<T>
  • Diago的 Mutex
  • System.IO.Path由ageektrapped
  • WeakReference由胡安曼努埃尔

方法和属性

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

提示与技巧

  • 事件处理程序的好方法由Andreas HR Nilsson提供
  • 大写的比较由约翰
  • 访问匿名types没有由dpreflection
  • 一个快速的方法来延迟实例化收集属性由威尔
  • 类似于JavaScript的匿名内联函数由roosteronacid

其他

  • 由kokos的netmodules
  • LINQBridge Duncan Smart
  • 并行扩展由Joel Coehoorn

这不是C#本身,但我没有看到任何真正使用System.IO.Path.Combine()的人。 实际上,整个Path类是非常有用的,但没有人使用它!

我敢打赌,每个生产应用程序都有以下代码,即使它不应该:

 string path = dir + "\\" + fileName; 

lambdas和types推理被低估。 Lambdas可以有多个语句,并且自动它们兼容为一个兼容的委托对象 (只需确保签名匹配),如下所示:

 Console.CancelKeyPress += (sender, e) => { Console.WriteLine("CTRL+C detected!\n"); e.Cancel = true; }; 

请注意,我没有new CancellationEventHandler也不需要指定senderetypes,它们可以从事件中推导出来。 这就是为什么编写整个delegate (blah blah)麻烦,这也需要你指定参数的types。

在这种情况下, Lambdas不需要返回任何东西 ,types推断是非常强大的。

顺便说一句,你总是可以返回使Lambdas在function编程意义上的Lambdas 。 例如,下面是一个使lambda处理Button.Click事件的lambda:

 Func<int, int, EventHandler> makeHandler = (dx, dy) => (sender, e) => { var btn = (Button) sender; btn.Top += dy; btn.Left += dx; }; btnUp.Click += makeHandler(0, -1); btnDown.Click += makeHandler(0, 1); btnLeft.Click += makeHandler(-1, 0); btnRight.Click += makeHandler(1, 0); 

注意链接: (dx, dy) => (sender, e) =>

这就是为什么我很高兴能够参加函数式编程课程:-)

除了C中的指针,我认为这是你应该学习的另一个基本的东西:-)

来自Rick Strahl :

你可以链接? 运算符,以便您可以执行一堆空比较。

 string result = value1 ?? value2 ?? value3 ?? String.Empty; 

别名仿制药:

 using ASimpleName = Dictionary<string, Dictionary<string, List<string>>>; 

它允许你使用ASimpleName ,而不是Dictionary<string, Dictionary<string, List<string>>>

当你在很多地方使用相同的通用大型复杂事物时使用它。

从CLR通过C# :

标准化string时,强烈build议您使用ToUpperInvariant而不是ToLowerInvariant,因为Microsoft已经优化了用于执行大写比较的代码

我记得有一次我的同事在比较之前总是把string改成大写。 我一直很好奇他为什么这样做,因为我觉得先把它转换成小写更“自然”。 现在读完这本书后,我知道为什么。

我最喜欢的技巧是使用null coalesce运算符和括号为我自动实例化集合。

 private IList<Foo> _foo; public IList<Foo> ListOfFoo { get { return _foo ?? (_foo = new List<Foo>()); } } 

避免检查空事件处理程序

在声明中添加一个空的委托给事件,在调用它之前总是检查事件是否为null是很棒的。 例:

 public delegate void MyClickHandler(object sender, string myValue); public event MyClickHandler Click = delegate {}; // add empty delegate! 

让你这样做

 public void DoSomething() { Click(this, "foo"); } 

而不是这个

 public void DoSomething() { // Unnecessary! MyClickHandler click = Click; if (click != null) // Unnecessary! { click(this, "foo"); } } 

请参阅这个相关的讨论和Eric Lippert关于这个主题的博客文章 (以及可能的缺点)。

一切,再加上

1)隐式generics(为什么只在方法而不在类?)

 void GenericMethod<T>( T input ) { ... } //Infer type, so GenericMethod<int>(23); //You don't need the <>. GenericMethod(23); //Is enough. 

2)带一个参数的简单lambdaexpression式:

 x => x.ToString() //simplify so many calls 

3)匿名types和初始者:

 //Duck-typed: works with any .Add method. var colours = new Dictionary<string, string> { { "red", "#ff0000" }, { "green", "#00ff00" }, { "blue", "#0000ff" } }; int[] arrayOfInt = { 1, 2, 3, 4, 5 }; 

另一个:

4)自动属性可以有不同的范围:

 public int MyId { get; private set; } 

谢谢@pzycoman提醒我:

5)命名空间别名(不是你可能需要这种特殊的区别):

 using web = System.Web.UI.WebControls; using win = System.Windows.Forms; web::Control aWebControl = new web::Control(); win::Control aFormControl = new win::Control(); 

我不知道“as”这个关键字已经有一段时间了。

 MyClass myObject = (MyClass) obj; 

VS

 MyClass myObject = obj as MyClass; 

如果obj不是MyClass,则第二个将返回null,而不是抛出类转换exception。

我喜欢的两件事是自动属性,所以你可以进一步折叠你的代码:

 private string _name; public string Name { get { return _name; } set { _name = value; } } 

 public string Name { get; set;} 

还有对象初始化器:

 Employee emp = new Employee(); emp.Name = "John Smith"; emp.StartDate = DateTime.Now(); 

 Employee emp = new Employee {Name="John Smith", StartDate=DateTime.Now()} 

genericstypes中的“default”关键字:

 T t = default(T); 

如果T是一个引用types,则返回'null';如果是int,则返回0;如果是boolean,则返回false。

一般的属性,但最重要的是DebuggerDisplay 。 节省你几年。

@告诉编译器忽略string中的任何转义字符。

只是想澄清这一个…它并没有告诉它忽略转义字符,它实际上告诉编译器将string解释为文字。

如果你有

 string s = @"cat dog fish" 

它将实际打印出来(注意它甚至包括用于缩进的空格):

 cat dog fish 

我认为C#(.NET 3.5)中最为人们所不了解的特性之一是expression式树 , 特别是当与generics和Lambdas结合在一起时。 这是一种创buildAPI的方法,像NInject和Moq这样的更新的库正在使用。

例如,假设我想用API注册一个方法,并且该API需要获取方法名称

鉴于这个类:

 public class MyClass { public void SomeMethod() { /* Do Something */ } } 

以前,看到开发人员用string和types(或其他基本上基于string的)来做这件事是很常见的:

 RegisterMethod(typeof(MyClass), "SomeMethod"); 

那么,这很糟糕,因为缺乏强大的打字。 如果我重命名“SomeMethod”呢? 现在,在3.5中,我可以用强types的方式做到这一点:

 RegisterMethod<MyClass>(cl => cl.SomeMethod()); 

其中RegisterMethod类使用Expression<Action<T>>像这样:

 void RegisterMethod<T>(Expression<Action<T>> action) where T : class { var expression = (action.Body as MethodCallExpression); if (expression != null) { // TODO: Register method Console.WriteLine(expression.Method.Name); } } 

这是我现在爱上Lambdas和Expression Trees的一大原因。

我会想到“ 收益率 ”。 一些像[DefaultValue()]这样的属性也是我的最爱。

“ var ”关键字更为人所知,但是您也可以在.NET 2.0应用程序中使用它(只要您使用.NET 3.5编译器并将其设置为输出2.0代码)似乎不是很知道好。

编辑:kokos,感谢指出? 运营商,这确实很有用。 由于它有点难以谷歌(因为??只是被忽略),这里是该运营商的MSDN文档页面: ?? 运算符(C#参考)

我倾向于发现大多数C#开发人员不知道“可空”types。 基本上,可以有一个空值的原语。

 double? num1 = null; double num2 = num1 ?? -100; 

将一个可以为null的double num1设置为null,如果num1为null,则将一个普通的double num2设置为num1-100

http://msdn.microsoft.com/en-us/library/1t3y8s4s(VS.80).aspx

关于可空types还有一件事:

 DateTime? tmp = new DateTime(); tmp = null; return tmp.ToString(); 

这是返回String.Empty。 检查此链接了解更多详情

这里有一些有趣的隐藏的C#特性,以无证的C#关键字的forms:

 __makeref __reftype __refvalue __arglist 

这些都是未公开的C#关键字(甚至Visual Studio可以识别它们!),这些关键字在generics之前被添加到更高效的装箱/拆箱。 他们与System.TypedReference结构协调工作。

还有__arglist,用于可变长度参数列表。

有一点人们不太了解的是System.WeakReference – 一个非常有用的类,它跟踪一个对象,但仍然允许垃圾收集器收集它。

最有用的“隐藏”function将是yield return关键字。 这不是真的隐藏,但很多人不知道。 LINQ是build立在这个上面的; 它允许通过在引擎下生成状态机来执行延迟执行的查询。 Raymond Chen最近发布了关于内部细节的细节 。

工会(C ++共享内存类)在纯粹,安全的C#

不诉诸不安全的模式和指针,你可以让类成员共享类/结构中的内存空间。 鉴于以下课程:

 [StructLayout(LayoutKind.Explicit)] public class A { [FieldOffset(0)] public byte One; [FieldOffset(1)] public byte Two; [FieldOffset(2)] public byte Three; [FieldOffset(3)] public byte Four; [FieldOffset(0)] public int Int32; } 

您可以通过操作Int32字段来修改字节字段的值,反之亦然。 例如,这个程序:

  static void Main(string[] args) { A a = new A { Int32 = int.MaxValue }; Console.WriteLine(a.Int32); Console.WriteLine("{0:X} {1:X} {2:X} {3:X}", a.One, a.Two, a.Three, a.Four); a.Four = 0; a.Three = 0; Console.WriteLine(a.Int32); } 

输出这个:

 2147483647 FF FF FF 7F 65535 

只需添加使用System.Runtime.InteropServices;

使用@作为关键字的variables名称。

 var @object = new object(); var @string = ""; var @if = IpsoFacto(); 

如果你想退出你的程序而不调用任何finally块或finalizer使用FailFast :

 Environment.FailFast() 

从方法返回匿名types并访问成员而不reflection。

 // Useful? probably not. private void foo() { var user = AnonCast(GetUserTuple(), new { Name = default(string), Badges = default(int) }); Console.WriteLine("Name: {0} Badges: {1}", user.Name, user.Badges); } object GetUserTuple() { return new { Name = "dp", Badges = 5 }; } // Using the magic of Type Inference... static T AnonCast<T>(object obj, T t) { return (T) obj; } 

Here's a useful one for regular expressions and file paths:

 "c:\\program files\\oldway" @"c:\program file\newway" 

The @ tells the compiler to ignore any escape characters in a string.

Mixins. Basically, if you want to add a feature to several classes, but cannot use one base class for all of them, get each class to implement an interface (with no members). Then, write an extension method for the interface , ie

 public static DeepCopy(this IPrototype p) { ... } 

Of course, some clarity is sacrificed. 但它的作品!

Not sure why anyone would ever want to use Nullable<bool> though. 🙂

True, False, FileNotFound ?

This one is not "hidden" so much as it is misnamed.

A lot of attention is paid to the algorithms "map", "reduce", and "filter". What most people don't realize is that .NET 3.5 added all three of these algorithms, but it gave them very SQL-ish names, based on the fact that they're part of LINQ.

"map" => Select
Transforms data from one form into another

"reduce" => Aggregate
Aggregates values into a single result

"filter" => Where
Filters data based on a criteria

The ability to use LINQ to do inline work on collections that used to take iteration and conditionals can be incredibly valuable. It's worth learning how all the LINQ extension methods can help make your code much more compact and maintainable.

 Environment.NewLine 

for system independent newlines.

If you're trying to use curly brackets inside a String.Format expression…

 int foo = 3; string bar = "blind mice"; String.Format("{{I am in brackets!}} {0} {1}", foo, bar); //Outputs "{I am in brackets!} 3 blind mice" 
  1. ?? – coalescing operator
  2. using ( statement / directive ) – great keyword that can be used for more than just calling Dispose
  3. readonly – should be used more
  4. netmodules – too bad there's no support in Visual Studio

@Ed, I'm a bit reticent about posting this as it's little more than nitpicking. However, I would point out that in your code sample:

 MyClass c; if (obj is MyClass) c = obj as MyClass 

If you're going to use 'is', why follow it up with a safe cast using 'as'? If you've ascertained that obj is indeed MyClass, a bog-standard cast:

 c = (MyClass)obj 

…is never going to fail.

Similarly, you could just say:

 MyClass c = obj as MyClass; if(c != null) { ... } 

I don't know enough about .NET's innards to be sure, but my instincts tell me that this would cut a maximum of two type casts operations down to a maximum of one. It's hardly likely to break the processing bank either way; personally, I think the latter form looks cleaner too.

Maybe not an advanced technique, but one I see all the time that drives me crazy:

 if (x == 1) { x = 2; } else { x = 3; } 

can be condensed to:

 x = (x==1) ? 2 : 3;