提问



在我从这个问题中了解到以下内容后,我想到了这一点:


where T : struct


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


我们中的一些人甚至掌握了泛型,匿名类型,lambdas,LINQ等...... [104] [105] [106] [107]


但是,即使C#粉丝,瘾君子,专家几乎不知道C#最隐藏的功能或技巧是什么?


到目前为止,以下是显示的功能:







关键字




  • yield作者Michael Stum

  • var作者Michael Stum

  • using() kokos的陈述

  • readonly by kokos

  • as Mike Stone

  • as/is作者Ed Swangren

  • as/is(改进)由Rocketpants

  • default by deathofrats

  • global:: by pzycoman

  • using()由AlexCuse封锁

  • volatile作者:JakubŠturc

  • extern alias作者:JakubŠturc



属性




  • DefaultValueAttribute作者Michael Stum

  • ObsoleteAttribute作者DannySmurf

  • DebuggerDisplayAttribute by Stu

  • DebuggerBrowsableDebuggerStepThrough by bdukes

  • ThreadStaticAttribute by marxidad

  • FlagsAttribute作者:Martin Clarke

  • ConditionalAttribute作者:AndrewBurns



语法




  • ??(coalesce nulls)operator by kokos

  • Nick Berardi的数字标记

  • where T:new作者:LarsMæhlum

  • Keith的隐式泛型

  • Keith的单参数lambdas

  • Keith的自动属性

  • Keith的命名空间别名

  • 使用@ by Patrick
  • 的逐字字符串文字
  • enum lfoust的数值

  • @variablenames by marxidad

  • event marxidad的运营商

  • 按Portman格式化字符串括号

  • xanadont的属性访问器可访问性修饰符

  • JasonS的有条件(三元)算子(?:)

  • checkedunchecked运营商Binoj Antony

  • implicit and explicit运营商Flory



语言功能




  • Brad Barker的可空类型

  • Keith的匿名类型

  • __makeref __reftype __refvalue作者:Judah Himango

  • lomaxx的对象初始化程序

  • David在达科他州格式化字符串

  • marxidad的扩展方法

  • partial Jon Erickson的方法

  • John Asbeck的预处理程序指令

  • DEBUG Robert Durgin的预处理器指令

  • SefBkn的运算符重载

  • 通过chakrit键入推理

  • Rob Gough将布尔运算符提升到新的水平

  • 传递值类型变量作为没有拳击的接口由Roman Boiko

  • 以编程方式确定Roman Boiko
  • 声明的变量类型
  • Chris的静态构造函数

  • 使用linoster by roosteronacid轻松实现眼睛/浓缩ORM映射

  • __arglist作者:Zac Bowling



Visual Studio功能




  • 在Himadri的编辑器中选择文本块

  • DannySmurf的片段



框架




  • TransactionScope by KiwiBastard

  • DependantTransaction by KiwiBastard

  • Nullable<T>作者:IainMH

  • Mutex by Diago

  • System.IO.Path by ageektrapped

  • WeakReference作者:Juan Manuel



方法和属性




  • String.IsNullOrEmpty() KiwiBastard的方法

  • List.ForEach() KiwiBastard的方法

  • 威尔·迪恩的
  • BeginInvoke()EndInvoke()方法

  • Nullable<T>.HasValueNullable<T>.Value属性由Rismo

  • GetValueOrDefault John Sheehan的方法



提示&花样




  • Andreas H.R. Nilsson的事件处理程序的好方法

  • John的大写比较

  • 通过dp
  • 访问没有反射的匿名类型
  • Will
  • 懒惰地实例化集合属性的快捷方法
  • 来自roosteronacid的类似JavaScript的匿名内联函数



其他




  • netmodules by kokos

  • Duncan Smart的LINQBridge

  • Joel Coehoorn的并行扩展


最佳参考


这不是C#本身,但我没有看到任何人真正使用System.IO.Path.Combine()到他们应该的程度。事实上,整个Path类非常有用,但是没有人使用它! [108] [[ [121] [[[123] [125] [127] [128] [130] [132] [[ [134] [136] [[ [[ [[ [164] [[ [[​​]] [190] [192] [[


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


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

其它参考1


lambdas和type inferrence 被低估了。 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中的指针,我认为这是你应该学习的另一个基本的东西:-)

其它参考2


来自Rick Strahl:[194]


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


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

其它参考3


别名仿制药:


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


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


当你在很多地方使用相同的通用大而复杂的东西时使用它。

其它参考4



  从CLR到C#:

  
  规范化字符串时,它是高度的
  建议您使用
  ToUpperInvariant而不是
  ToLowerInvariant因为 Microsoft有
  优化了执行代码
  大写比较




我记得有一次我的同事在比较之前总是将字符串换成大写字母。我一直想知道为什么他这样做,因为我觉得首先转换为小写更自然。现在读完这本书后,我知道为什么。

其它参考5


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


private IList<Foo> _foo;

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

其它参考6


避免检查空事件处理程序


在声明时向事件添加一个空委托,禁止在调用它之前始终检查该事件是否真棒。例:


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关于此主题的博客文章(以及可能的缺点)。 [198]

其它参考7


其他一切,加上


1)隐式泛型(为什么只有方法而不是类?)


void GenericMethod<T>( T input ) { ... }

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


2)带有一个参数的简单lambda:


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


3)匿名类型和初始化者:


//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();

其它参考8


很长一段时间我都不知道关键词。


MyClass myObject = (MyClass) obj;


VS


MyClass myObject = obj as MyClass;


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

其它参考9


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


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()}

其它参考10


泛型类型中的default关键字:


T t = default(T);


如果T是引用类型,则返回null;如果是int,则返回0;如果是布尔值,则返回false,
等等。

其它参考11


一般属性,但大多数是DebuggerDisplay。为你节省数年。[199]

其它参考12



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



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


如果你有


string s = @"cat
             dog
             fish"


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


cat
             dog
             fish

其它参考13


我认为C#(.NET 3.5)最不受欢迎和鲜为人知的功能之一是表达树,特别是与Generics和Lambdas结合使用时。这是一种API创建方法,像NInject和Moq这样的新库正在使用。[200]


例如,假设我想要使用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和表情树的一个重要原因。

其它参考14


我会想到屈服。像[[DefaultValue()]]这样的一些属性也是我的最爱。[201] [202]


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


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

其它参考15


我倾向于发现大多数C#开发人员都不了解可空类型。基本上,原语可以具有空值。


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


将可为空的双精度 num1 设置为null,然后将常规double, num2 设置为 num1 或 -100 如果 num1 为null。


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


关于Nullable类型还有一件事:


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


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

其它参考16


以下是一些有趣的隐藏C#功能,以未记录的C#关键字的形式:


__makeref

__reftype

__refvalue

__arglist


这些是未记录的C#关键字(甚至Visual Studio识别它们!),这些关键字是为了在泛型之前更有效的装箱/拆箱而添加的。它们与System.TypedReference结构协同工作。


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


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


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

其它参考17


Unions(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;

其它参考18


使用@作为关键字的变量名。


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

其它参考19


如果你想退出程序而不调用任何finally块或终结器,请使用FailFast:[210]


Environment.FailFast()

其它参考20


从方法返回匿名类型并访问成员而不进行反射。


// 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;
}

其它参考21


这对于正则表达式和文件路径来说非常有用:


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


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

其它参考22


混入。基本上,如果要向多个类添加一个功能,但不能为所有类使用一个基类,请让每个类实现一个接口(没有成员)。然后,为接口编写扩展方法,即


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


当然,牺牲一些清晰度。但它的确有效!

其它参考23



  不知道为什么有人会想要使用Nullable< bool>。 :-)



真,假,FileNotFound?[211]

其它参考24


这个不是隐藏的,因为它被误解了。


很多注意力都集中在算法map,reduce和filter上。大多数人都没有意识到,.NET 3.5添加了所有这三种算法,但它给了它们非常的SQL-ish名称,基于它们是LINQ的一部分。



  map=>选择
转换数据
  从一种形式到另一种形式

  
  reduce=> Aggregate
Aggregates
  将值转换为单个结果

  
  filter=> Where
过滤数据
  基于标准



使用LINQ对过去采用迭代和条件的集合进行内联工作的能力非常有价值。值得了解所有LINQ扩展方法如何帮助您的代码更加紧凑和可维护。

其它参考25


Environment.NewLine


用于系统独立的换行符。

其它参考26


如果您在String.Format表达式中尝试使用大括号...


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"

其它参考27



  1. ? - 合并运营商

  2. using(statement/directive) - 一个很好的关键字,不仅可以用来调用Dispose

  3. readonly - 应该使用更多

  4. netmodules - 太糟糕了,Visual Studio中没有支持


其它参考28


@Ed,我对发布这个内容有点保持沉默,因为它只不过是挑剔。但是,我会在你的代码示例中指出:[212] [213] [214] [215]


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


如果您要使用是,为什么要使用as进行安全演员?如果您已经确定obj确实是MyClass,那么沼泽标准演员:


c = (MyClass)obj


......永远不会失败。


同样,你可以说:


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


我不太了解.NET的内部信息,但我的直觉告诉我,这会最多将两个类型转换操作减少到最多一个。它不太可能以任何方式破坏处理银行;就个人而言,我认为后一种形式看起来也更清晰。

其它参考29


也许不是一种先进的技术,但我总是看到让我疯狂的一种技术:


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


可以浓缩为:


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