C#的隐藏特性?




hidden-features (20)

在我从这个问题中得知以下内容后,我想起了这件事

where T : struct

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

我们中有些人甚至掌握了Generics匿名类型lambdasLINQ等等。

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

以下是迄今为止显示的功能:


关键词

属性

句法

语言功能

Visual Studio功能

  • Himadri编辑器中选择文本块
  • DannySmurf的片段

骨架

方法和属性

提示与技巧

其他


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

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

如果你有

string s = @"cat
             dog
             fish"

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

cat
             dog
             fish

Not sure why anyone would ever want to use Nullable<bool> though. :-)

True, False, FileNotFound ?


  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

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

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

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

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

顺便说一下,你总是可以返回使Lambdas处于函数式编程意义上的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中的指针,我认为这是你应该学习的另一个基本的东西:-)


避免检查空事件处理程序

在声明中为事件添加一个空的委托,在调用它之前始终检查事件是否为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撰写的关于此主题的博客文章 (以及可能的缺点)。


@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.


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"

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;

Returning anonymous types from a method and accessing members without 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;
}

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.


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


以下是一些有趣的隐藏C#特性,采用无证C#关键字的形式:

__makeref

__reftype

__refvalue

__arglist

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

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

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

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


别名仿制药:

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

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

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


如果你想在不调用任何finally块或finalizer的情况下退出你的程序,使用FailFast

Environment.FailFast()

我会想到“ yield ”。 一些像DefaultValueAttribute这样的属性也是我的最爱。

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

编辑:kokos,谢谢你指出了?? 操作员,这确实非常有用。 由于它对Google来说有点难(因为??只是忽略了),下面是该运算符的MSDN文档页面: ?? ??


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

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

关于可空类型还有一件事:

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

它返回String.Empty。 查看this链接了解更多详情


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

private IList<Foo> _foo;

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

我认为C#(.NET 3.5)中最受关注和鲜为人知的特性之一是表达式树特别是当与泛型和Lambdas结合使用时。 这是API创建的一种方法,像NInject和Moq这样的新型库正在使用。

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

鉴于这个类:

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

之前,看到开发人员使用字符串和类型(或其他主要基于字符串的其他语言)来执行此操作非常常见:

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

那么,由于缺乏强类型,这很糟糕。 如果我将“SomeMethod”重命名? 现在,在3.5中,我可以用强类型的方式做到这一点:

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的一个重要原因。


泛型类型中的'default'关键字:

T t = default(T);

如果T是引用类型,则返回'null';如果是int,则返回0;如果是boolean,则返回false。


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

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

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




hidden-features