当前位置:  开发笔记 > 编程语言 > 正文

C#的隐藏功能?

如何解决《C#的隐藏功能?》经验,为你挑选了230个好方法。

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

where T : struct

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

我们中的一些人甚至掌握了Generics,匿名类型,lambdas,LINQ等......

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

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


关键词

yield由迈克尔·葡萄汁

var由迈克尔·葡萄汁

using()kokos的声明

readonly由kokos

as由迈克·斯通

as/ is由埃德Swangren

as/ is(改进)由Rocketpants

default由deathofrats

global::通过pzycoman

using()由块AlexCuse

volatile作者:JakubŠturc

extern alias作者:JakubŠturc

属性

DefaultValueAttribute由迈克尔·葡萄汁

ObsoleteAttribute作者DannySmurf

DebuggerDisplayAttribute由斯图

DebuggerBrowsableDebuggerStepThrough通过bdukes

ThreadStaticAttribute通过marxidad

FlagsAttribute作者:Martin Clarke

ConditionalAttribute作者:AndrewBurns

句法

??(合并空值)运算符由kokos

Nick Berardi的数字标记

where T:new作者:LarsMæhlum

Keith的隐式泛型

Keith的单参数lambdas

基思的汽车房产

Keith命名空间别名

使用@ by Patrick的逐字字符串文字

enum价值由lfoust

@variablenames来自marxidad

event马克西德的经营者

由Portman格式化字符串括号

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

JasonS的条件(三元)运算符(?:)

checked和Binoj Antony的unchecked运营商

implicit and explicitFlory的运营商

语言特色

Brad Barker的可空类型

Keith的匿名类型

__makeref __reftype __refvalue由Judah Himango提供

lomaxx的对象初始值设定项

David在Dakota中格式化字符串

马克西德的延伸方法

partialJon Erickson的方法

John Asbeck的预处理程序指令

DEBUGRobert Durgin的预处理器指令

运算符由SefBkn重载

用chakrit键入推理

布尔运算符带到一个新的水平由罗布·高夫

传递值类型变量作为接口而没有罗马博伊科的拳击

以编程方式确定Roman Boiko声明的变量类型

Chris的静态构造函数

使用灵芝酸的 LINQ,更容易在眼睛/浓缩ORM映射

__arglist作者:Zac Bowling

Visual Studio功能

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

通过片段DannySmurf

骨架

TransactionScope由KiwiBastard

DependantTransaction由KiwiBastard

Nullable作者:IainMH

Mutex通过Diago

System.IO.Path通过ageektrapped

WeakReference作者:Juan Manuel

方法和属性

String.IsNullOrEmpty()KiwiBastard的方法

List.ForEach()KiwiBastard的方法

BeginInvoke(),EndInvoke()通过以下方法威尔院长

Nullable.HasValueNullable.Value通过性能Rismo

GetValueOrDefaultJohn Sheehan的方法

提示与技巧

Andreas HR Nilsson对事件处理程序的好方法

John的大写比较

访问匿名类型而不用dp反射

Will的一种快速实例化集合属性的方法

roosteronacid的类似JavaScript的匿名内联函数

其他

网络模块由kokos提供

LINQBridge by Duncan Smart

并行扩展由乔尔Coehoorn

ageektrapped.. 752

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

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

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


chakrit.. 585

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

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

请注意,我没有new CancellationEventHandler也不必指定类型,sender并且e它们可以从事件中推断出来.这就是为什么编写整体不那么麻烦,delegate (blah blah)这也需要您指定参数类型.

Lambdas不需要返回任何内容,类型推断在这样的上下文中非常强大.

顺便说一下,你可以随时返回Lambdas,它们在函数式编程意义上使Lambdas成为可能.例如,这是一个lambda,它使lambda处理Button.Click事件:

Func 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中的指针,我认为这是你应该学习的另一个基本的东西:-)



1> ageektrapped..:

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

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

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



2> chakrit..:

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

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

请注意,我没有new CancellationEventHandler也不必指定类型,sender并且e它们可以从事件中推断出来.这就是为什么编写整体不那么麻烦,delegate (blah blah)这也需要您指定参数类型.

Lambdas不需要返回任何内容,类型推断在这样的上下文中非常强大.

顺便说一下,你可以随时返回Lambdas,它们在函数式编程意义上使Lambdas成为可能.例如,这是一个lambda,它使lambda处理Button.Click事件:

Func 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中的指针,我认为这是你应该学习的另一个基本的东西:-)



3> jfs..:

来自Rick Strahl:

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

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



4> BlackTigerX..:

别名仿制药:

using ASimpleName = Dictionary>>;

它允许你使用ASimpleName,而不是Dictionary>>.

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



5> jfs..:

从CLR到C#:

规范化字符串时,强烈建议您使用ToUpperInvariant而不是ToLowerInvariant,因为Microsoft已优化用于执行大写比较的代码.

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


当您"将字符串转换为大写字母"时,您将创建第二个临时字符串对象.我认为这种比较不是首选,最好的方法是:String.Equals(stringA,stringB,StringComparison.CurrentCultureIgnoreCase)whcih根本不会创建这个一次性字符串.
转换为大写而不是小写也可以防止某些文化中的错误行为.例如,在土耳其语中,两个小写的i映射到相同的大写字母I.谷歌"turkish i"了解更多细节.
我尝试对ToUpperInvariant和ToLowerInvariant进行基准测试.我发现它们在.NET 2.0或3.5下的性能没有任何差别.当然不是任何保证"高度推荐"使用一个而不是另一个的东西.
在比较小写字符串无法完成的大写字符串时,您可以执行哪种优化?我不明白为什么一个人会比另一个更优秀.
ToUpperInvariant是首选,因为它使所有字符往返.请参阅http://msdn.microsoft.com/en-us/library/bb386042.aspx.为了比较,写一个"a".Equals("A",StringComparison.OrdinalIgnoreCase)`
在土耳其语中,映射是(i - >İ)和(ı - > I).所以"文件".ToUpper()!="文件"和类似的"文件".ToLower()!="文件".这就是为什么在某些情况下需要使用ToUpperInvariant()或ToLowerInvariant()的原因.
@ neilwhitaker1:使用*invariant*转换时不是问题.
@ neilwhitaker1:在土耳其语中我都映射了相同的大写字母并不是真的,它们都映射到不同的大写字母.所以我不明白为什么大写会比小写更好.
我阅读里希特引用的方式,他说大写字符串之间的比较是优化的.转换为上层并不比转换为下层更有效.

6> 小智..:

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

private IList _foo;

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


对于noo来说,它有点难以阅读,没有经验.但它的紧凑,包含程序员应该知道和理解的几种模式和语言功能.因此,虽然一开始很难,但它提供了学习的理由.
懒惰的实例化有些弊端,因为它是一个可怜的人选择,以避免考虑类不变量.它还有并发问题.
难道你不觉得难以阅读吗?
我总是被告知这是一种不好的做法,称一个财产不应该这样做.如果你有一个集合并将值设置为null,那么使用你的API会很奇怪.
@Joel除了将ListOfFoo设置为null既不是类合同的一部分也不是好习惯.这就是为什么没有一个二传手.这也是ListOfFoo保证返回集合而不是null的原因.它只是一个非常奇怪的抱怨,如果你做了两件坏事(制作一个setter并将一个集合设置为null),这将导致你的期望错误.我不建议在getter中做Environment.Exit().但这也与这个答案无关.
@jan我不确定那是怎么回事."获取"体外的行为是相同的.你是指在课堂上访问公共财产时绕过公共财产的做法吗?我个人认为这是不好的做法.伊恩说,如果我有一个二传手,那就太糟糕了; 是的,如果我用锤子击中我的头也会很糟糕,这就是为什么我不这样做.所以我仍然对他的担忧感到困惑.BRB,没有赤身裸体跳下悬崖.
现在这是一个很酷的技术:在null时将赋值内联!
@Theraot不管懒惰还是个更好的主意吗?
我通常用它作为.. return _foo = _foo ?? 新列表(); ... IMO更容易阅读.
@Ian:我想如果我跟踪并击败任何使用我的API的人,对任何使用它的人来说都会非常奇怪.也许我会从我的"愚蠢的事情中发现这一点,任何有感觉的人都不会做,但对我来说似乎是一个非常酷的想法".我无法理解你的评论与任何事情有什么关系.这令我难以置信."如果你做了些蠢事,那将是愚蠢的." 我想它有道理,但为什么我呢?我很困惑.
我认为Ian关于setter的观点很好:如果我正在使用该类并使用setter将ListOfFoo设置为null,那么下次我调用它时它将是非null这一事实打破了对属性应该如何应对的预期表现.因此,指出此模式不应与setter一起使用是正确的.
@Will我觉得这根本不难读,我甚至都不是C#程序员.但是,我仍然认为这对于一个房产来说并不是一个好的做法.延迟初始化的好处是什么?不多.为什么没有充分理由使对象的状态空间复杂化?该功能本身很整洁(虽然我不确定表达式的评估是如何被视为**隐藏的功能**...),但我认为这个特定的应用程序是一个坏主意.

7> andnil..:

避免检查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关于此主题的博客文章(以及可能的缺点).


我相信如果你依赖这种技术然后你必须序列化这个类就会出现问题.您将消除该事件,然后在反序列化时,您将获得一个NullRefference ....所以,人们可以坚持做事的"旧方式".它更安全.
快速配置文件测试显示,没有空测试的虚拟订阅事件处理程序大约是使用null测试的未订阅事件处理程序的2倍.没有空测试的多播事件处理程序占用了使用null测试的单播事件处理程序的大约3.5倍.
由于上述评论中的原因,这是一个可怕的建议.如果必须使代码看起来"干净",请使用扩展方法检查null然后调用该事件.有修改权限的人肯定应该在这个答案中添加缺点.
这通过始终具有自订户来避免需要空检查.即使是空事件,这也会带来您不想要的开销.如果没有订阅者,您根本不想激活事件,并不总是首先触发空虚事件.我会考虑这个糟糕的代码.
您仍然可以将事件处理程序设置为null,这样您仍然可以获得空引用,并且仍然存在竞争条件.
"你根本不想解雇它"的论点是BS.检查应明确限于事件基础结构,而不是用户.这是一种语言错误设计,应该修复.空订户列表是有效的订户列表!零是一个数字,黑色是一种颜色.
此外,在性能方面,它每次都必须调用一个空方法.
我不知道为什么这看起来如此优雅,看起来像是对我的黑客......出于同样的原因,为什么不将所有对象分配给某些东西,而不是在使用之前检查为null?此外,我同意P爸爸的说法,性能打击不值得节省打字.
帕维尔说得对,这首先应该是一个问题.这本应该被设计成语言.可能的原因是事件为空?也就是说,添加一个空委托是一个不太理想的解决方案.扩展方法更好,但创建一个调用方法仍然是最佳实践,这样您就可以更轻松地控制对事件的访问.例如,如果您决定允许子类引发事件,则可以简单地使invoker方法受到保护.扩展方法应该有助于编写调用者 - 而不是替换它们.
另请参阅此帖子以获取更多详细信息和替代方案:http://blogs.msdn.com/ericlippert/archive/2009/04/29/events-and-races.aspx
我真的不喜欢这种方法得到如此多的关注.你所采取的性能实际上有点大.
如果我理解正确的话,这会强制任何订阅的事件被多播而不是单播,结果会导致很大的性能损失.它还强制调用不会被调用的事件,这是另一个重大打击.不值得一点点输入它保存!
有人可以修改帖子,包括有关性能成本的信息吗?不是每个人都阅读评论.
没有充分理由你不应该修改答案.如果你认为这不好,请给出答案.其他人显然认为是.

8> Keith..:

其他一切,加上

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

void GenericMethod( T input ) { ... }

//Infer type, so
GenericMethod(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 {
    { "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();


我认为你已经能够用int [] nums = {1,2,3}初始化数组; 因为1.0 :)甚至不需要"new"关键字
在#3你可以做Enumerable.Range(1,5)
还有没有参数的lambda()=> DoSomething();
@Kirk Broadhurst - 你是对的 - "new web.Control()`也适用于这个例子.`::`语法强制它将前缀视为命名空间别名,所以你可以有一个名为`web`的类,而`web :: Control`语法仍然有用,而``web.Control`语法则不会'知道是否检查类或命名空间.因此,在执行命名空间别名时,我总是倾向于使用`::`.
我用过{get; 内部集合; 和{得到; 保护集; 所以这种模式是一致的.

9> Mike Stone..:

很长一段时间我都不知道"as"关键字.

MyClass myObject = (MyClass) obj;

VS

MyClass myObject = obj as MyClass;

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


不过不要过度.很多人似乎都使用as,因为他们更喜欢语法,即使他们想要(ToType)x的语义.
你可以滥用它,并在以后可能有一个InvalidCastException之前有一个NullReferenceException.
在"as"关键字的相同行中,"is"关键字同样有用.
如果通常情况下施法失败,这只会更有效.否则直接强制转换(类型)对象更快.直接强制转换抛出异常比返回null需要更长的时间.
我不相信它提供更好的性能.你有没有介绍过它?(显然虽然它在演员阵容失败时会发生......但是当你使用(MyClass)演员阵容时,失败是特殊的......并且非常罕见(如果它们发生的话),所以没有区别.

10> lomaxx..:

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

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


许多人没有意识到的是get和set可以具有不同的可访问性,例如:public string Name {get; 私人集;}
使用3.0编译器引入了自动属性.但由于编译器可以设置为输出2.0代码,因此它们可以正常工作.只是不要尝试在较旧的编译器中使用自动属性编译2.0代码!
只有自动属性的问题是似乎无法提供默认的初始化值.
@ANeves:不,不是.从该页面:**DefaultValueAttribute不会导致使用属性的值自动初始化成员.您必须在代码中设置初始值.**`[DefaultValue]`用于设计器,因此它知道是否以粗体显示属性(表示非默认值).
是否应注意自动属性仅是C#3.0功能?

11> 小智..:

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

T t = default(T);

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


另外:打字?作为Nullable 的快捷方式.default(int)== 0,但是default(int?)== null.

12> Stu..:

一般属性,但最重要的是DebuggerDisplay.为您节省数年.


使用DebuggerDisplay属性(MSDN):http://msdn.microsoft.com/en-us/library/x810d419.aspx

13> lomaxx..:

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

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

如果你有

string s = @"cat
             dog
             fish"

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

cat
             dog
             fish


是的它被称为逐字字符串.
如果输出显示也将打印出来的空间将更清楚.现在看起来似乎打印了新行字符但忽略了空格.

14> Jason Olson..:

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

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

鉴于此类:

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

之前,通常会看到开发人员使用字符串和类型(或其他主要基于字符串的方式)执行此操作:

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

嗯,这很糟糕,因为缺乏强力打字.如果我重命名"SomeMethod"怎么办?现在,在3.5中,我可以以强类型的方式执行此操作:

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

RegisterMethod类使用Expression>如下:

void RegisterMethod(Expression> action) where T : class
{
    var expression = (action.Body as MethodCallExpression);

    if (expression != null)
    {
        // TODO: Register method
        Console.WriteLine(expression.Method.Name);
    }
}

这是我现在爱上Lambdas和Expression Trees的一个重要原因.


我认为这些并不是那么鲜为人知,因为它们的理解程度较低.
我有一个反射实用程序类,它与FieldInfo,PropertyInfo等相同...

15> Michael Stum..:

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

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

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


默认值的文档说它并没有真正设置属性的值.它只是可视化工具和代码生成器的助手.
name的名字?operator是"Null Coalescing"运算符
至于DefaultValue:与此同时,一些图书馆使用它.ASP.net MVC在Controller Action的参数上使用DefaultValue(这对非可空类型非常有用).当然严格来说,这是一个代码生成器,因为该值不是由编译器设置的,而是由MVC的代码设置的.

16> Brad Barker..:

我倾向于发现大多数C#开发人员都不知道'可空'类型.基本上,可以具有空值的基元.

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

将可空双精度数num1设置为null,然后将常规双精度数num2设置为num1-100(如果num1为null).

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

关于Nullable类型还有一件事:

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

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


@ck:是的,int是System.Int32的别名,为T?是Nullable 的别名,但它不仅仅是*语法糖.它是语言的一部分.别名不仅使代码更易于阅读,而且更适合我们的模型.表达Nullable 为double?强调了如此包含的值是(或可能是)double的观点,而不仅仅是在Double类型上实例化的一些通用结构.(继续)
@P Daddy - 是的,int是System.Int32的语法糖.它们完全可以互换,就像int一样?=== Int32?=== Nullable === Nullable
...无论如何,争论不是关于别名(我想这只是一个很糟糕的比喻),但可以使用你喜欢的任何语法的可空类型确实是一种语言特征,而不仅仅是泛型的产物.你不能仅仅使用泛型来重现nullables的所有功能(比较/赋值null,运算符转发,底层类型的装箱或null,与null合并和`as`运算符的兼容性).单独的Nullable 是基本的,并且远非恒星,但作为语言的一部分的可空类型的概念是踢屁股.
那么"int"只是System.Int32的C#语法糖吗?实际上存在围绕Nullable类型构建的编译器支持,例如,将它们设置为null(仅使用通用结构不能完成),并将它们作为底层类型装箱.

17> Judah Gabrie..:

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

__makeref

__reftype

__refvalue

__arglist

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

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

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

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


[Peter Bromberg关于未记录关键字的更多细节](http://www.eggheadcafe.com/articles/20030114.asp).如果有理由使用它们,我仍然无法获得.

18> ZeroBugBounc..:

联合(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添加;


**警告:此方法没有考虑字节顺序.**这意味着您的C#代码在所有计算机上都不会以相同的方式运行.在little-endian CPU(首先存储最低有效字节)上,将使用所示的行为.但在大端CPU上,字节将与您的预期相反.请注意如何在生产代码中使用它 - 您的代码可能无法移植到某些移动设备和其他硬件,并且可能以非显而易见的方式中断(例如,两个文件表面上采用相同的格式,但实际上字节顺序相反).
@George,当您使用c联合声明通过套接字与遗留应用程序通信时,可以创造奇迹.
如果你想将浮点数作为位掩码操作,你有时需要说int和浮点数为0.特别是如果你想学习浮点数的新东西.
令人烦恼的是,如果您要使用这是一个结构,编译器将强制您在init函数中设置所有变量.所以如果你有:public A(int int32){Int32 = int32; 它将抛出"字段'一个'必须在控制权返回给调用者之前完全分配",所以你必须设置一个=两个=三个=四个= 0; 同样.
这有其用途,主要是二进制数据.我使用带有int32 @ 0的"Pixel"结构,以及用于4个组件@ 0,1,2和3的四个字节.非常适合快速轻松地操作图像数据.

19> Mark Cidade..:

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

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


如果您曾想使用asp.net MVC HTML帮助程序并定义HTML类,您将很高兴知道您可以使用@class,因此它不会被识别为class关键字
@zihotki:错了.var a = 5; Console.WriteLine(@a); 打印5
那么,它的原因是CLI要求它与可能使用C#关键字作为成员名称的其他语言的互操作性
为什么要将关键字用作变量名?在我看来,这将使代码更易于阅读和混淆.
非常适合扩展方法.public static void DoSomething(这个Bar @this,string foo){...}
就个人而言,我认为"Class @ class"比"Class clazz"更好
我经常使用`@ return`作为返回变量,`@ default`作为默认值,`@ this`作为扩展方法的第一个参数,等等.当我像这样使用它时,我认为它确实有助于清晰度代码 - 特别是对于扩展方法.
这不是一个功能,@只是允许用于命名的符号,如_和其他许多符号(名称'@this'不等于名称'this')

20> Jan Banniste..:

如果要在不调用任何finally块或终结器的情况下退出程序,请使用FailFast:

Environment.FailFast()


请注意,此方法还会创建内存转储并将消息写入Windows错误日志.
真?你可以这样做?

21> denis philli..:

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

// 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(object obj, T t)
{
   return (T) obj;
}


那真的不能给你任何东西.这实际上很危险.如果修改GetUserTuple以返回多种类型,该怎么办?演员阵容将在运行时失败.关于C#/ .Net的一个好处是编译时检查.创建一个新类型会好得多.
虽然很酷,但这似乎是一个相当糟糕的设计选择.你基本上在两个地方定义了匿名类型.那时,只需声明一个真正的结构并直接使用它.
@Jason我确实说它可能没什么用,但令人惊讶(而且我认为是隐藏的).
@George:这样的约定会被称为... struct?
这个技巧被命名为'cast by sample',如果返回匿名类型的方法位于另一个程序集中,它将无效.

22> Patrick..:

这是正则表达式和文件路径的一个有用的:

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

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


另外,@ constant接受里面的换行符.将多行脚本分配给字符串时非常完美.
换句话说,不要忘记逃避引号只是加倍.[code] var candy = @"我喜欢""红色""糖果手杖."; [/ code]
@new也是变量而不是关键字:@this,@ int,@ return,@ interface ...等等:)
我倾向于使用Path.Combine构建路径.我肯定用@正则表达式!

23> Dmitri Neste..:

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

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

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


如果他们只允许扩展属性!!!! 我讨厌必须编写一个请求只读属性的扩展方法....
是的,我认为这是扩展方法的真正力量.它们基本上允许实现接口方法.

24> Michael Stum..:

不知道为什么有人会想要使用Nullable .:-)

真,假,FileNotFound?


如果期望用户回答"是",那么如果问题尚未得到回答,那么null将是合适的
可空类型可以方便地与数据库进行交互,其中表列通常可以为空.
存储ThreeState CheckBox的值
是的,不,也许?
与在SQL中一样:是/否/未知.
使用enum是一种更好的方法,而不是使用可空的布尔值
在填充ddl员工时,我使用了可空的bool.仅有效=真.只有InActive - 假.活动和非活动= null

25> Brad Wilson..:

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

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

"map"=>选择
将数据从一种形式转换为另一种形式

"reduce"=> Aggregate
Aggregates值为单个结果

"filter"=> Where
根据条件过滤数据

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


@Brad,那个(where)是一个过滤操作.尝试进行地图操作而不选择...
在我看来,LINQ是C#发生的重大事情:http://stackoverflow.com/questions/2398818/whats-the-next-big-thing-after-linq-closed

26> nimish..:
Environment.NewLine

用于系统独立的换行符.


值得指出的是,这是特定于应用程序的主机平台 - 所以如果要创建用于其他系统的数据,则应该适当地使用\n或\ r \n.
关于这个问题的烦人之处在于它不包含在紧凑的框架中.

27> Portman..:

如果您尝试在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"


@Kyralessa:实际上,是的,它们是大括号,但"花括号"是它们的替代名称.`[`和`]`是方括号,`<`和`>`是尖括号.见http://en.wikipedia.org/wiki/Bracket.
你是对的.但是当我评论时,它没有说"卷曲"括号.
非常好的指出.记住我的第一个String.Format看起来像:String.Format("{0}我在大括号{1} {2} {3}","{","}",3,"盲老鼠"); 一旦我发现逃避这些是通过使用{{和}}完成的,我很高兴:)

28> kokos..:

    ?? - 合并运营商

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

    readonly - 应该多用

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


using也可用于将长命名空间别名为更方便的字符串,即:使用ZipEncode = MyCompany.UtilityCode.Compression.Zip.Encoding; 还有更多:http://msdn.microsoft.com/en-us/library/sf0df423.aspx
@LucasAardvark:正如J Steen所说,它被称为零合并运算符.搜索!
这真的不是一回事.调用Dispose时,可以使用using语句,当使用using指令的别名类型时.
万一你想要#1的名字(就像你对三元运算符所做的那样),?? 被称为空合并运算符.

29> Dogmang..:

@Ed,我对发布这个有点保持沉默,因为它只不过是挑剔.但是,我会在您的代码示例中指出:

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

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

c = (MyClass)obj

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

同样,你可以说:

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

我不太了解.NET的内部结构,但我的直觉告诉我,这将最多将两个类型转换操作减少到最多一个.无论如何,它几乎不可能破坏处理银行; 就个人而言,我认为后一种形式看起来也更清洁.


如果强制转换为精确类型(当对象为"A"时强制转换为"A",而不是从其中派生),则直接投射比"as"快〜3倍.当转换派生类型(当对象是"B"时,转换为"A",派生自"A")时,直接转换比"as"慢约0.1x."是",然后"as"只是愚蠢.
`is`和`as`不会做用户演员.因此,如果obj是从MyClass派生的(或者具有隐式系统定义的强制转换),上面的代码会询问`is`运算符.另外,`is`在`null`上失败.这两种边缘情况对您的代码都很重要.例如,您可能想写:`if(obj == null || obj是MyClass)c =(MyClass)obj;`但这与以下内容完全不同:`try {c =(MyClass)obj; } catch {}`因为前者不会执行任何用户定义的转换,但后者会执行.没有`null`检查,当obj`为'null`时,前者也不会设置`c`.
我为此运行了测试,将`IEnumerable `转换为`List `,并将`object`(`new object()`)转换为`IEnumerable `,以确保没有错误:直接投射:5.43ns,is->投射:6.75ns,投射:5.69ns.然后测试无效的强制转换:直接投射:3125000ns,投射:5.41ns.结论:不要担心1%的因素,只是确保你使用is/as当演员表可能无效时,导致异常(如果处理的话)与演员相比非常慢,我们说的是578000因素较慢.记住最后一部分,其余部分无所谓(.Net FW 4.0,发布版)
不,但你可以写"if((c = obj as MyClass)!= null)".
在IL中,强制转换为CASTCLASS但是as /是转到ISINST指令.

30> JasonS..:

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

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

可以浓缩为:

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


它实际上被称为"条件运算符" - 它是*a*三元运算符,因为它需要三个参数.http://en.wikipedia.org/wiki/Conditional_operator
可以浓缩为x ++; 好吧没有意义^^
我想因为它们不是同一个东西,作为操作员而不是声明.我更喜欢自己的第一种方法.它更加一致且易于扩展.运算符不能包含语句,因此只需要扩展正文,您就必须将该三元运算符转换为if语句
三元运算符已在我的小组中被禁止.有些人不喜欢它,虽然我从来不明白为什么.
@Guillaume:考虑x的所有值:x = 2 + System.Math.Min(1,System.Math.Abs​​(x-1));
@François:不,这与x ++不同......不要以为x是1,2或3 ......它可以是任何东西.

31> Ralph Carave..:

许多人没有意识到他们可以使用OrdinalIgnoreCase来比较字符串,而不必使用someString.ToUpper().这消除了额外的字符串分配开销.

if( myString.ToUpper() == theirString.ToUpper() ){ ... }

if( myString.Equals( theirString, StringComparison.OrdinalIgnoreCase ) ){ ... }


这可以很容易地改变为null安全:var isEqual = String.Equals(a,b,StringComparison.OrdinalIgnoreCase);

32> Cristian Lib..:

刚刚学习,匿名类型可以从变量名称推断属性名称:

string hello = "world";
var o = new { hello };
Console.WriteLine(o.hello);



33> Nick Berardi..:

老实说,定义中的专家应该知道这些东西.但要回答你的问题:内置类型表(C#参考)

标记数字的编译器广为人知:

Decimal = M
Float = F
Double = D

// for example
double d = 30D;

然而,这些更加模糊:

Long = L
Unsigned Long = UL
Unsigned Int = U


M语法来自名为Money的旧VB类型.M ==金钱==十进制.
每当我处理小数时,我都要抬头看m.它只是我还是不是很直观?:)
不,任何小于Int32的东西都会由编译器根据它左边的类型自动推断出来
有一个字节吗?
@Nick:很好 - 我喜欢学习代码背后的历史.

34> ljs..:

我喜欢在列表中查找内容: -

bool basketContainsFruit(string fruit) {
  return new[] { "apple", "orange", "banana", "pear" }.Contains(fruit);
}

而不是:-

bool basketContainsFruit(string fruit) {
  return fruit == "apple" || fruit == "orange" || fruit == "banana" ||
    fruit == "pear";
}

在实践中没有那么多,但是将项目与搜索主题相匹配的想法可能非常有用+简洁.


但是你可以使用开关来充分利用两个世界(至少对于这个例子,或任何整数类型).示例如下,但由于缺少换行符,可读性在评论中受损:`switch(fruit){case"apple":case"orange":case"banana":case"pear":return true; 默认值:return false; }`
public static bool In (T value,params T [] items){return items.Contains(value); if(fruit.In("apple","orange","banana","pear")){...}
@P爸爸 - 是的,但确实遭受了很多额外的语法.@Fowl - 如果案件没有代码,你可以有所体会(当然,直到遇到崩溃的情况).

35> DAC..:

InternalsVisibleTo属性是一个众所周知的属性,但在某些情况下可以增加方便.它基本上允许另一个程序集能够访问定义程序集的"内部"元素.


我经常使用它来编写针对另一个组件的内部成员的单元测试.这样,可以从部署中排除单元测试.

36> jcruz..:

这是C#4.0中字符串类的新方法:

String.IsNullOrWhiteSpace(String value)

是时候了.


现在我已经尝试过,我当然更喜欢[Haack的方法](http://haacked.com/archive/2010/06/16/null-or-empty-coalescing.aspx).您为AsNullIfEmpty和AsNullIfWhiteSpace组合了字符串扩展方法.通过这种方式,您可以在合并运算符中使用结果:`SomeString.AsNullIfEmpty()?? "默认值"`.
制作自己的util方法会产生什么问题:`(myString ??"").Trim()==""`
在记录中,我绝对HATE string.Empty.除了""之外还有什么?静态字段与实际字符串的性能优势可以忽略不计:http://stackoverflow.com/questions/263191/in-c-should-i-use-string-empty-or-string-empty-or
我真的不喜欢"".你应该使用string.Empty(myString ?? string.Empty).Trim()== string.Empty,因为它传达了更多.

37> 小智..:

我在使用ReSharper时选择了这个:

隐式方法组转换

//If given this:
var myStrings = new List(){"abc","def","xyz"};
//Then this:
myStrings.ForEach(s => Console.WriteLine(s));
//Is equivalent to this:
myStrings.ForEach(Console.WriteLine);

有关详细信息,请参阅" C#中的隐式方法组转换 ".



38> Steve Dunn..:

在调试时,您可以键入$exceptionWatch\QuickWatch\Immediate窗口并获取有关当前帧异常的所有信息.如果你有第一次机会异常开启,这非常有用!



39> JamesSugrue..:

System.Transactions中的TransactionScope和DependentTransaction是一种在.NET中使用事务处理的轻量级方法 - 它不仅适用于数据库事务

我很惊讶地发现很多开发人员都不知道String.IsNullOrEmpty

List.ForEach - 使用委托方法遍历您的通用列表

还有更多,但这是我头脑中最明显的三个......


List.ForEach比foreach更快或者(;;)完全疯狂.ForEach使用方法/函数委托来实现该行为.这首先意味着更糟糕的缓存局部性,因为代码通常比实际循环更远(在内存中)执行.其次,您需要做的就是验证速度较慢是查看生成的本机代码.List.ForEach的内容比你想象的要多得多.
现在还有String.IsNullOrWhitespace

40> Wyzfen..:

Dictionary.TryGetValue(K键,输出V值)

作为一个支票和一个进入.而不是;

if(dictionary.ContainsKey(key)) 
{
    value = dictionary[key];
    ...
}

你可以做;

if(dictionary.TryGetValue(key, out value)) 
{ ... }

并且已设置该值.


TryGetValue的另一个好处是,如果您的字典是同步的,则没有竞争条件.与ContainsKey相比,其他线程可以删除您在调用之间寻找的项目.
如果键为null,则抛出TryGetValue - 这对于避免axceptions非常重要.我使用TryGetValue2()扩展方法来解决这个问题.
在字典中查找null似乎比查找不存在的值更可能是代码错误.我个人很高兴它抛出异常;)

41> Christian Hu..:

条件string.Format:

根据数字是正数,负数还是零,对数字应用不同的格式.

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)


这与reg表达式类似,非常有用,但我也记不起来了.我用padleft和padright处理上面的东西.

42> Mark Cidade..:

事件实际上是代理,任何委托对象都可以附加多个函数,并分别使用+ =和 - =运算符从中分离.

也可以使用add/remove控制事件,类似于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;



43> 小智..:

不要忘记转到.


不,让我们忘记吧.;)
+1.如何在不弄乱bool变量或将整个事物移动到函数或lambda的情况下从多级循环中突破?它应该存在于语言中的原因......
不,让我们滥用它直到王国来临.;)

44> Mike Two..:

更多的运行时功能,但我最近了解到有两个垃圾收集器.工作站gc和服务器gc.Workstation是客户端版本的Windows的默认设置,但服务器在多核计算机上要快得多.


   
      
   

小心.服务器gc需要更多内存.


在Windows的服务器SKU(Server 2003等)上,默认使用服务器GC.工作站GC是客户端SKU(如Vista)的默认设置.

45> Grokys..:

我看不到上面这个 - 我直到最近才意识到你可以做的一个是从另一个调用一个构造函数:

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


我认为你的意思是:public Example(int value1):this(*value1*,"Default Value"){}

46> Binoj Antony..:

其他未充分利用运营商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


只是提醒大家确切的MaxValue是什么!
而不是32767和评论,如何`short.MaxValue`?

47> JoshL..:

用"扔;" 而不是"抛出前"; 保留堆栈跟踪

如果在不添加其他信息的情况下重新抛出异常,请使用"throw"而不是"throw ex".catch块中的空"throw"语句将发出特定的IL,它会在保留原始堆栈跟踪的同时重新抛出异常."throw ex"将堆栈跟踪丢失到异常的原始源.



48> Jon Skeet..:

我遇到的一些隐藏功能:

stackalloc 它允许您在堆栈上分配数组

没有显式参数列表的匿名方法,可以隐式转换为具有非out/ref参数的任何委托类型(对于事件非常方便,如前面的注释中所述)

很多人都不知道究竟是什么事件(添加/删除一对方法,比如属性的get/set); C#中的字段事件确实声明了变量事件

==!=运营商也可以被重载返回比其他类型bool.奇怪但真实.

C#3中的查询表达式转换在某些方面非常"简单" - 这意味着你可以让它做一些非常奇怪的事情.

可空类型具有特殊的装箱行为:空值被装箱到空引用,并且您也可以从null拆分为可空类型.



49> Himadri..:

我只是想在没有评论的情况下复制该代码.因此,诀窍是只需按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键并选择矩形,无需取消注释.

看一下这个.


VS2010不仅可以选择,而且可以这种方式编辑文本 - 例如在每行的开头添加单词"private",只需通过alt选择行之前的空格并开始输入 - 从而纠正不良的离开练习在多个字段声明的同时关闭单词.
+1此问题中有一个"Visual Studio功能"部分,您的答案非常适合.
它不仅仅是Visual Studio功能.您可以在Microsoft Word Notepad2等中执行此操作.
有趣的Visual Studio功能,但问题是关于C#.

50> Konamiman..:

@David在达科他州:

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

我曾经这样做,直到我发现String类有一个构造函数,允许你以更干净的方式做同样的事情:

new String('-',22);



51> Jakub Šturc..:

该挥发性关键字告诉一个字段可以由多个线程同时进行修改编译器.


嘿,这不完全正确.volatile关键字指示编译器在每次从字段读取时生成获取栅栏,并在每次写入字段时生成释放栅栏.获取栅栏可防止其他读/写在栅栏前移动; 释放栅栏可防止在栅栏后移动其他读/写.在这里阅读更多内容:http://bit.ly/hycbVI

52> 小智..:

我喜欢的几件事:

- 如果你创建一个类似的界面

 public interface SomeObject where T : SomeObject, new()

你强制从这个接口继承的任何东西都包含一个无参数的构造函数.这对我碰到的几件事非常有用.

- 使用匿名类型动态创建有用的对象:

var myAwesomeObject = new {Name="Foo", Size=10};

- 最后,许多Java开发人员熟悉如下语法:

public synchronized void MySynchronizedMethod(){}

但是,在C#中,这不是有效的语法.解决方法是方法属性:

 [MethodImpl(MethodImplOptions.Synchronized)]
 public void MySynchronizedMethod(){}


"你强制从这个接口继承的任何东西都包含一个无参数的构造函数"严格来说,不,你没有 - 你强制任何实现你的接口的类来证明它知道实现接口的类的名称并且具有无参数构造函数.那不是一回事.A类:SomeObject {public A()// required}类B:SomeObject {} //编译正常,没有构造函数.
[MethodImpl(MethodImplOptions.Synchronized)] = lock(this)= bad
这些都是好主意.这个网站通常更喜欢每个答案一个想法,所以他们可以单独评级.我会给你三个评级:)

53> Tim Jarvis..:

params关键字,即

public void DoSomething(params string[] theStrings)
{
  foreach(string s in theStrings)
  {
    // Something with the Strings…
  }
}

叫做像

DoSomething(“The”, “cat”, “sat”, “on”, “the” ,”mat”);



54> andnil..:

Foreach使用Duck Typing

从Krzysztof Cwalinas的博客上解释,或无耻地偷窃.比任何事都更有趣的琐事.

对于支持foreach的对象,您不必实现IEnumerable.即,这不是约束,编译器不会检查它.检查的是那个

你的对象提供一个公共方法GetEnumerator的

没有参数

返回一个有两个成员的类型

    一个无参数的方法MoveNext,它返回一个布尔值

    具有返回Object的getter 的属性Current

例如,

class Foo
{
    public Bar GetEnumerator() { return new Bar(); }

    public struct Bar
    {
        public bool MoveNext()
        {
            return false;
        }

        public object Current
        {
            get { return null; }
        }
    }
}

// the following complies just fine:
Foo f = new Foo();
foreach (object o in f)
{
    Console.WriteLine("Krzysztof Cwalina's da man!");
}


棒极了!我没有知道......但是,与集合初始化器相同的东西......你需要的只是一个`Add(x)`方法.`public class MyList {public void Add(string s){}}`.然后你可以做`var l = new MyList {"a","b","c"};`...

55> core..:

静态构造函数.

实例:

public class Example
{
    static Example()
    {
        // Code to execute during type initialization
    }

    public Example()
    {
        // Code to execute during object initialization
    }
}

静态类:

public static class Example
{
    static Example()
    {
        // Code to execute during type initialization
    }
}

MSDN 说:

静态构造函数用于初始化任何静态数据,或执行仅需执行一次的特定操作.在创建第一个实例或引用任何静态成员之前自动调用它.

例如:

public class MyWebService
{
    public static DateTime StartTime;

    static MyWebService()
    {
        MyWebService.StartTime = DateTime.Now;
    }

    public TimeSpan Uptime
    {
        get { return DateTime.Now - MyWebService.StartTime; }
    }
}

但是,您也可以轻松地做到:

public class MyWebService
{
    public static DateTime StartTime = DateTime.Now;

    public TimeSpan Uptime
    {
        get { return DateTime.Now - MyWebService.StartTime; }
    }
}

因此,当您确实需要使用静态构造函数时,您将很难找到任何实例.

MSDN提供有关静态构造函数的有用说明:

静态构造函数不接受访问修饰符或具有参数.

在创建第一个实例
或引用任何静态成员之前,会自动调用静态构造函数来初始化类.

无法直接调用静态构造函数.

用户无法控制何时在程序中执行静态构造函数.

静态构造函数的典型用法是当类使用日志文件并且构造函数用于将
条目写入此文件时.


当构造函数
可以调用LoadLibrary方法时,静态构造函数在为非托管代码创建包装类时也很有用.

如果静态构造函数抛出异常,则运行时将不会
再次调用它,并且该类型将
在运行程序的应用程序域的生命周期内保持未初始化状态.

最重要的注意事项是,如果静态构造函数中发生错误,TypeIntializationException则抛出a并且无法向下钻取到有问题的代码行.相反,你必须检查TypeInitializationExceptionInnerException成员,这是具体原因.



56> bdukes..:

System.Diagnostics命名空间中的其他一些属性非常有用.

DebuggerBrowsable将允许您隐藏调试器窗口中的变量(我们将其用于公开属性的所有私有后备变量).除此之外,DebuggerStepThrough使调试器跨过该代码,对于哑属性非常有用(如果可以依赖于C#3.0编译器,则可能应该转换为自动属性).举个例子

[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private string nickName;
public string NickName    {
    [DebuggerStepThrough]
    get { return nickName; }
    [DebuggerStepThrough]
    set { this.nickName = value; }
}


嗯...整洁的技巧,但我想我会在调试器中看到字段在我的班级中有所有残缺
谨防!DebuggerStepThrough非常方便,但应该仅用于简单的实现.在调试时,调试器会完全跳过标有此属性的方法,就好像它们不在那里一样(它会隐藏实现细节,因为您将单步执行它).不会触发方法内的断点.

57> Shital Shah..:

C#+ CLR:

    Thread.MemoryBarrier:大多数人都不会使用它,MSDN上有一些不准确的信息.但是,如果您知道错综复杂,那么您可以进行漂亮的无锁同步.

    volatile, Thread.VolatileRead, Thread.VolatileWrite:很少有人能够使用这些,甚至更少的人了解他们避免和介绍的所有风险:).

    ThreadStatic变量:过去几年中只有一种情况我发现ThreadStatic变量绝对是神派并且不可或缺.例如,当你想为整个调用链做某事时,它们非常有用.

    fixed 关键字:当你想要像C++一样快地访问大型数组的元素时,这是一个隐藏的武器(默认情况下,C#强制执行绑定检查,这会降低速度).

    default(typeName)关键字也可以在泛型类之外使用.创建struct的空副本很有用.

    我使用的一个方便的功能是DataRow[columnName].ToString()始终返回非空值.如果数据库中的值为NULL,则为空字符串.

    当您希望开发人员注意时,使用Debugger对象会自动中断,即使他/她没有启用异常时自动中断:

#if DEBUG  
    if (Debugger.IsAttached)  
        Debugger.Break();  
#endif

    您可以为复杂丑陋的泛型类型添加别名,这样您就不必一次又一次地复制它们.您也可以在一个地方更改该类型.例如,

    using ComplicatedDictionary = Dictionary>;
    ComplicatedDictionary myDictionary = new ComplicatedDictionary();



58> Michael Mead..:

关闭

由于匿名代表被添加到2.0,我们已经能够开发闭包.它们很少被程序员使用,但提供了很多好处,例如即时代码重用.考虑一下这段代码:

bool changed = false;

if (model.Prop1 != prop1)
{
    changed = true;
    model.Prop1 = prop1;
}
if (model.Prop2 != prop2)
{
    changed = true;
    model.Prop2 = prop2;
}
// ... etc. 

请注意,上面的if语句执行类似的代码片段,但一行代码除外,即设置不同的属性.这可以通过以下方式缩短,其中变化的代码行作为参数输入到Action对象中,具体名称为setAndTagChanged:

bool changed = false;
Action setAndTagChanged = (action) => 
{ 
    changed = true; 
    action(); 
};

if (model.Prop1 != prop1) setAndTagChanged(() => model.Prop1 = prop1);
if (model.Prop2 != prop2) setAndTagChanged(() => model.Prop2 = prop2);

在第二种情况下,闭包允许您change在lambda中调整变量的范围,这是解决此问题的简明方法.

另一种方法是使用另一个未使用的特征,即"等于"二进制赋值运算符.以下代码显示了如何:

private bool conditionalSet(bool condition, Action action)
{
    if (condition) action();
    return condition;
}

// ...

bool changed = false;
changed |= conditionalSet(model.Prop1 == prop1, () => model.Prop1 = prop1);
changed |= conditionalSet(model.Prop2 == prop2, () => model.Prop2 = prop2);



59> Hugoware..:

我说使用某些系统类进行扩展方法非常方便,例如System.Enum,你可以做类似下面的事情......

[Flags]
public enum ErrorTypes : int {
    None = 0,
    MissingPassword = 1,
    MissingUsername = 2,
    PasswordIncorrect = 4
}

public static class EnumExtensions {

    public static T Append (this System.Enum type, T value) where T : struct
    {
        return (T)(ValueType)(((int)(ValueType) type | (int)(ValueType) value));
    }

    public static T Remove (this System.Enum type, T value) where T : struct
    {
        return (T)(ValueType)(((int)(ValueType)type & ~(int)(ValueType)value));
    }

    public static bool Has (this System.Enum type, T value) where T : struct
    {
        return (((int)(ValueType)type & (int)(ValueType)value) == (int)(ValueType)value);
    }

}

...

//used like the following...

ErrorTypes error = ErrorTypes.None;
error = error.Append(ErrorTypes.MissingUsername);
error = error.Append(ErrorTypes.MissingPassword);
error = error.Remove(ErrorTypes.MissingUsername);

//then you can check using other methods
if (error.Has(ErrorTypes.MissingUsername)) {
    ...
}

这只是一个例子 - 方法可以使用更多的工作......



60> Luke Foust..:

能够使枚举类型具有除int之外的值(默认值)

public enum MyEnum : long
{
    Val1 = 1,
    Val2 = 2
}

此外,您可以为该枚举分配任何数值:

MyEnum e = (MyEnum)123;


我相信编译器必须支持这个以支持标志.所以给定上面的枚举,如果你做MyEnum val = MyEnum.Val1 | MyEnum.Val2最终会得到一个超出已定义的可能值的值.(在这种情况下为3).由于你可以对枚举进行二进制算术,理论上它们可以有很多可能的值.
你也可以让[Flags]告诉enum是基于标志的
为什么您希望能够为枚举分配任何旧值?是不是限制价值选择的枚举点?

61> Judah Gabrie..:

我今天刚刚发现了这个 - 我和C#一起工作了5年!

它是命名空间别名限定符:

extern alias YourAliasHere;

您可以使用它来加载相同类型的多个版本.这在维护或升级方案中非常有用,在这种情况下,您的类型的更新版本在某些旧代码中不起作用,但您需要将其升级到新版本.Slap在命名空间别名限定符上,编译器将允许您在代码中使用这两种类型.



62> Keith Bluest..:

RealProxy允许您为现有类型创建自己的代理.

这是超级先进的,我还没有看到其他人使用它 - 这可能意味着它对大多数人来说也没那么有用 - 但这是其中一件很有趣的事情.

基本上,.NET RealProxy类允许您为另一种类型创建所谓的透明代理.透明在这种情况下意味着它看起来完全像它的客户端的代理目标对象 - 但它实际上不是:它是您的类的实例,它是从RealProxy派生的.

这使您可以在客户端和在真实目标对象上调用的任何方法或属性之间应用强大而全面的拦截和"中介"服务.将此功能与工厂模式(IoC等)结合使用,您可以回送透明代理而不是真实对象,允许您拦截对真实对象的所有调用,并在每次方法调用之前和之后执行操作.事实上,我相信这是.NET用于跨应用程序域,进程和机器边界进行远程处理的功能:.NET拦截所有访问,将序列化信息发送到远程对象,接收响应,并将其返回到您的代码.

也许一个例子将清楚地说明这是如何有用的:我为我作为企业架构师的最后一份工作创建了一个参考服务堆栈,它指定了整个部门中任何新WCF服务的标准内部组合("堆栈").该模型要求(例如)Foo服务实现的数据访问层IDAL: 创建一个Foo,读取一个Foo,更新一个Foo,删除一个Foo.服务开发人员使用提供的公共代码(来自我)来定位和加载服务所需的DAL:

IDAL GetDAL(); // retrieve data access layer for entity T

该公司的数据访问策略经常受到性能挑战.作为一名架构师,我无法监视每个服务开发人员,以确保他/她编写了一个高性能的数据访问层.但是我在GetDAL工厂模式中可以做的是为请求的DAL 创建透明代理(一旦公共服务模型代码定位DLL并加载它),并使用高性能时序API来分析对所有方法的调用. DAL.然后对落后者进行排名只是通过降低总时间来排序DAL呼叫时间.这种过度开发分析(例如在IDE中)的优点是它也可以在生产环境中完成,以确保SLA.

下面是我为"实体分析器"编写的测试代码示例,它是为单行创建任何类型的分析代理的常用代码:

[Test, Category("ProfileEntity")]
public void MyTest()
{
    // this is the object that we want profiled.
    // we would normally pass this around and call
    // methods on this instance.
    DALToBeProfiled dal = new DALToBeProfiled();

    // To profile, instead we obtain our proxy
    // and pass it around instead.
    DALToBeProfiled dalProxy = (DALToBeProfiled)EntityProfiler.Instance(dal);

    // or...
    DALToBeProfiled dalProxy2 = EntityProfiler.Instance(dal);

    // Now use proxy wherever we would have used the original...
    // All methods' timings are automatically recorded
    // with a high-resolution timer
    DoStuffToThisObject(dalProxy);

    // Output profiling results
    ProfileManager.Instance.ToConsole();
}

同样,这允许您拦截客户端在目标对象上调用的所有方法和属性!在RealProxy派生类中,您必须覆盖Invoke:

[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
[SecurityPermission(SecurityAction.LinkDemand, 
    Flags = SecurityPermissionFlag.Infrastructure)] // per FxCop
public override IMessage Invoke(IMessage msg)
{
    IMethodCallMessage msgMethodCall = msg as IMethodCallMessage;
    Debug.Assert(msgMethodCall != null); // should not be null - research Invoke if this trips. KWB 2009.05.28

    // The MethodCallMessageWrapper
    // provides read/write access to the method 
    // call arguments. 
    MethodCallMessageWrapper mc =
        new MethodCallMessageWrapper(msgMethodCall);

    // This is the reflected method base of the called method. 
    MethodInfo mi = (MethodInfo)mc.MethodBase;

    IMessage retval = null;

    // Pass the call to the method and get our return value
    string profileName = ProfileClassName + "." + mi.Name;

    using (ProfileManager.Start(profileName))
    {
        IMessage myReturnMessage =
           RemotingServices.ExecuteMessage(_target, msgMethodCall);

        retval = myReturnMessage;
    }

    return retval;
}

.NET能做什么并不令人着迷?唯一的限制是目标类型必须MarshalByRefObject派生.我希望这对某人有帮助.



63> John K..:
任意嵌套范围{}


1.更好的范围界定行为

{在成员内的任何地方},{仅使用大括号},{没有控制语句}.

void MyWritingMethod() {

    int sameAge = 35;


    { // scope some work
        string name = "Joe";
        Log.Write(name + sameAge.ToString());
    }


    { // scope some other work
        string name = "Susan";
        Log.Write(name + sameAge.ToString());
    }

    // I'll never mix up Joe and Susan again
}

在大型,混乱或过时的成员(不是它们应该存在)中,它可以帮助我防止使用错误的变量名称.范围更精细的东西.

2.用于代码美化或视觉语义

例如,此XML编写代码遵循实际生成的XML的缩进级别(即Visual Studio将相应地缩进范围大括号)

XmlWriter xw = new XmlWriter(..);

//
xw.WriteStartElement("root");
{
    //
    xw.WriteStartElement("game");
    {
        //#
        for (int i = 0; i < scores.Length; ++i) // multiple scores
            xw.WriteElementString("score", scores[i].ToString());

    }
    //
    xw.WriteEndElement();
}
//
xw.WriteEndElement();

3.模仿'with'语句

(另一个用于保持临时工作不在主范围内的用法)
由Patrik提供:有时用于模仿C#中的VB"with-statement".

var somePerson = this.GetPerson();  // whatever 
{ 
    var p = somePerson; 
    p.FirstName = "John"; 
    p.LastName = "Doe"; 
    //... 
    p.City = "Gotham"; 
} 

对于挑剔的程序员.



64> Rismo..:

没有隐藏,但我认为很多开发人员都没有在可空类型上使用HasValue和Value属性.

        int? x = null;
        int y;
        if (x.HasValue)
            y = x.Value;


不,人们喜欢写:y = x ?? 默认值.
为了清楚起见,(x!= null)和(x.HasValue)导致相同的IL.
像这样:int?X; if(x!= null)
我更喜欢`x!= null`而不是`x.HasValue`.
如何在不使用HasValue的情况下使用可空类型?

65> Surgical Cod..:

我最喜欢的是

global::

用我们的一些第三方代码提供商逃避名称空间地狱的关键字......

例:

global::System.Collections.Generic.List myList =
    new global::System.Collections.Generic.List();



66> Zyphrax..:

我已经阅读了所有七页,我错过了这些:

的string.join

我已经看到很多for循环将项目列表转换为带分隔符的字符串.确保不以分隔符开头并且不以分隔符结束总是很痛苦.内置方法使这更容易:

String.Join(",", new String[] { "a", "b", "c"});

TODO在评论中

不是C#功能,更像是Visual Studio功能.当您使用TODO开始发表评论时,它会添加到您的Visual Studio任务列表中(查看 - >任务列表.评论)

// TODO: Implement this!
throw new NotImplementedException();

扩展方法符合泛型

您可以将扩展方法与Generics结合使用,当您考虑本主题前面的技巧时,可以向特定接口添加扩展

public static void Process(this T item) where T:ITest,ITest2 {}

Enumerable.Range

只想要一个整数列表?

Enumerable.Range(0, 15)

我会试着想一些......


它确实是一个VS提示,但除了TODO,我们还使用:QUESTION,HACK,BUG,FIX,REFACTOR,RESOURCE :(使用你得到提示/代码的网址)你可以通过工具添加任意数量的>选项>任务列表和像Hudson这样的CI选择它们很棒!
`Enumerable.Range`可以用作`for`循环的替代.而不是做这个`for(i = 0; i <15; i ++)`,你可以这样做`foreach(int in Enumerable.Range(0,15))`.

67> codymanix..:

您可以在一个using语句中"使用"多个对象.

using (Font f1= new Font("Arial", 10.0f), f2 = new Font("Arial", 10.0f))
{
    // Use f1 and f2.
}

请注意,已经有一个答案表明您可以这样做:

using (Font f1= new Font("Arial", 10.0f))
using (Font f2 = new Font("Arial", 10.0f))
{    }

这与我的不同.


请注意,如果它们属于同一类型,则只能在同一个using语句中指定多个对象.

68> Kim Tranjan..:

宽度 string.Format()

Console.WriteLine("Product: {0,-7} Price: {1,5}", product1, price1);
Console.WriteLine("Product: {0,-7} Price: {1,5}", product2, price2);

产生

替代文字

来自 Prabir的博客| 隐藏的C#功能



69> Buildstarted..:

类型定义

有人发布他们错过了typedef,但你可以这样做

using ListOfDictionary = System.Collections.Generic.List>;

并声明为

ListOfDictionary list = new ListOfDictionary();


@Lyubomyr等对这个问题有90%的答案.
请记住,此方法最多只限于当前文件.您需要将其添加到项目中每个文件的顶部.
Niklaos,检查它是一个编译时替换而不是运行时的东西.

70> nialljsmith..:

我喜欢关键字continue.

如果你在循环中遇到一个条件并且不想做任何事情而只是推进循环只需坚持"继续;".

例如:

foreach(object o in ACollection)
{
  if(NotInterested)
     continue;
}


+1来抵消Jon Cage.如果继续/休息是邪恶的,那么返回也是如此.continue/break可用于提前终止循环(继续仅终止当前迭代,break终止整个循环),就像返回可用于提前终止函数一样.早期可能比深层嵌套ifs好得多.并且goto不是邪恶的,只是不经常需要.它在"意大利面条代码"中得到了不好的代表,这些代码通常是在缺乏更好结构的旧语言中创建的.拥有这些更好的结构会导致更清晰的代码,更少需要goto,但不是没有.使用正确的工具完成工作.
+1以双重抵消Jon Cage.部分是因为他无法拼写_spaghetti_.使用continue,break和goto是完全有效的手段.如果你过度使用它们,你可能做错了什么,但代码有时会调用它.如果开发人员很难跟随它,那么他们应该寻找新的职业,因为如果有人记得BASIC,那么很多现代编程的祖先根源.
-1:使用continue,break等距离goto(这是邪恶的)一步之遥.它们使复杂程序中的执行流程难以遵循,并最终导致您编写spaghetty代码.
将偏移量加倍+1:虽然我可能会在示例中使用if(!NotInterested){...},但我不会将其拖入此处.switch-case需要break,并在满足条件时逃离循环.return和停止函数一样重要,因为在一个interation中就是break.

71> TheSmurf..:

我个人最喜欢的两个,我看到很少使用:

    片段(特别是对于属性,对Visual Studio 2008来说更好)

    该ObsoleteAttribute


更好的是,例如:写"for"或"switch",然后双击"tab"键
我非常喜欢交换机代码段.使得枚举变得更容易;)
片段虽然是Visual Studio的一个功能吗?而不是C#/编译器?

72> xanadont..:

@lomaxx我前几天也学到了(同时我学到了你的提示)是你现在可以在同一个属性上拥有不同的访问级别:

public string Name { get; private set;}

这样只有类本身才能设置Name属性.

public MyClass(string name) { Name = name; }


保护集; 对基类非常有用.

73> jfs..:

使用语句嵌套

通常我们这样做:

StringBuilder sb = new StringBuilder();
using (StringWriter sw = new StringWriter()) {
    using (IndentedTextWriter itw = new IndentedTextWriter(sw)) {
        ... 
    }
}

但我们可以这样做:

StringBuilder sb = new StringBuilder();
using (StringWriter sw = new StringWriter())
using (IndentedTextWriter itw = new IndentedTextWriter(sw)) {
    ... 
}


这是使用关键字特有的功能吗?它看起来就像一个典型的语法,其中一个语句(如if,using,while)对下一个语句或语句块进行操作.在我读过的代码样式指南中,不推荐在这些情况下省略花括号.
您可以对每个可以嵌套的语句执行此操作.
它不是特定于使用,你可以写:if(Something)使用(new Pen())使用(new Brush())for(;;)DoSometing();

74> IgorM..:

完全访问调用堆栈:

public static void Main()
{
  StackTrace stackTrace = new StackTrace();           // get call stack
  StackFrame[] stackFrames = stackTrace.GetFrames();  // get method calls (frames)

  // write call stack method names
  foreach (StackFrame stackFrame in stackFrames)
  {
    Console.WriteLine(stackFrame.GetMethod().Name);   // write method name
  }
}

所以,如果你拿第一个 - 你知道你在做什么功能.如果你正在创建一个辅助跟踪功能 - 在最后一个之前拿一个 - 你就会知道你的来电者.


如果您处于调试或发布模式,可能会让您失望的一件事.堆栈跟踪可能因优化而有所不同.这使我陷入了一种不幸的尝试,以规范某些方法的来电者:http://moffdub.wordpress.com/2008/07/01/method-regulator-pattern/
您可以使用来帮助解决此问题.

75> cllpse..:

类似JavaScript的匿名内联函数

返回一个字符串:

var s = new Func(() =>
{
    return "Hello World!";
})();

返回一个更复杂的对象:

var d = new Func>(() =>
{
    return new Dictionary
    {
        { 0, "Foo" },
        { 1, "Bar" },
        { 2, "..." }
    };
})();

一个真实的用例:

var tr = new TableRow();

tr.Cells.AddRange
(
    new[]
    {
        new TableCell { Text = "" },
        new TableCell { Text = "" },
        new TableCell { Text = "" },

        new TableCell
        {
            Text = new Func(() =>
            {
                return @"Result of a chunk of logic, without having to define
                         the logic outside of the TableCell constructor";
            })()
        },

        new TableCell { Text = "" },
        new TableCell { Text = "" }
    }
);

注意:您不能在内联函数的范围内重用变量名.


替代语法

// The one-liner
Func Add = (a, b) => Convert.ToString(a + b);

// Multiple lines
Func Add = (a, b) =>
{
    var i = a + b;

    return i.ToString();
};

// Without parameters
Func Foo = () => "";

// Without parameters, multiple lines
Func Foo = () =>
{
    return "";
};

缩短字符串并添加水平省略号...

Func Shorten = s => s.Length > 100 ? s.Substring(0, 100) + "…" : s;



76> Mark Cidade..:

还有ThreadStaticAttribute为每个线程创建一个唯一的静态字段,因此您可以拥有强类型的线程本地存储.

即使扩展方法不是那么秘密(LINQ基于它们),对于实用程序帮助程序方法来说它们的有用性和可读性可能并不那么明显:

//for adding multiple elements to a collection that doesn't have AddRange
//e.g., collection.Add(item1, item2, itemN);
static void Add(this ICollection coll, params T[] items)
 { foreach (var item in items) coll.Add(item);
 }

//like string.Format() but with custom string representation of arguments
//e.g., "{0} {1} {2}".Format(c=>c.Name,"string",new object(),new Custom())
//      result: "string {System.Object} Custom1Name"
static string Format(this string format, Func select, params object[] args)
 { for(int i=0; i < args.Length; ++i)
    { var x = args[i] as T;
      if (x != null) args[i] = select(x);
    }
   return string.Format(format, args);
 }



77> juan..:

它实际上并不是一个C#隐藏的功能,但我最近发现了WeakReference类,并被它所震撼(虽然这可能是因为它帮助我找到了解决我的特定问题的事实......)



78> Bryan Watts..:

按行字段初始化在一行中:

public StringBuilder Builder
{
    get { return _builder ?? (_builder = new StringBuilder()); }
}

我不确定我对C#支持赋值表达式的看法,但是,嘿,它在那里:-)


重复:http://stackoverflow.com/questions/9033/hidden-features-of-c/58945#58945

79> Roman Boiko..:

轻松确定声明变量的类型(从我的回答):

using System;
using System.Collections.Generic;

static class Program
{
    public static Type GetDeclaredType(T x)
    {
        return typeof(T);
    }

    // Demonstrate how GetDeclaredType works
    static void Main(string[] args)
    {
        IList iList = new List();
        List list = null;

        Console.WriteLine(GetDeclaredType(iList).Name);
        Console.WriteLine(GetDeclaredType(list).Name);
    }
}

结果:

IList`1
List`1

它的名字(借用"获取变量名"):

static void Main(string[] args)
{
    Console.WriteLine("Name is '{0}'", GetName(new {args}));
    Console.ReadLine();
}

static string GetName(T item) where T : class
{
    var properties = typeof(T).GetProperties();
    return properties[0].Name;
}

结果: Name is 'args'


其实还不错.首先看一下样本是误导性的.我会记住这个伎俩.:)
@ acidzombie24:你会得到`List'1`作为第一个结果,而不是`IList'1`.而null引用异常而不是第二个结果.`GetType()`返回一个对象的类型,而不是声明的变量类型.

80> GvS..:

该Environment.UserInteractive财产.

UserInteractive属性为Windows进程或IIS等服务报告错误,该服务在没有用户界面的情况下运行.如果此属性为false,则不显示模式对话框或消息框,因为没有用户可以与之交互的图形用户界面.



81> Jason Willia..:

从C/C++迁移的程序员可能会错过这个:

在C#中,%(模数运算符)适用于浮点数!



82> Incognito..:

AppDomain.UnhandledException事件也是隐藏的候选者.

此事件提供未捕获异常的通知.它允许应用程序在系统默认处理程序向用户报告异常并终止应用程序之前记录有关异常的信息.如果有足够的有关应用程序状态的信息,则可以采取其他措施 - 例如保存程序数据以便以后恢复.建议小心,因为在未处理异常时程序数据可能会损坏.

我们可以看到,即使在这个网站上,也有很多人想知道为什么他们的应用程序没有启动,为什么崩溃等等.AppDomain.UnhandledException事件对于这种情况非常有用,因为它提供了至少记录应用原因的可能性失败.



83> Frep D-Orong..:

C#?? null合并运算符 -

没有真正隐藏,但很少使用.可能是因为很多开发人员在看到有条件的时候跑了一英里?操作员,所以当他们看到这个时他们跑两个.用过的:

string mystring = foo ?? "foo was null"

而不是

string mystring;
if (foo==null)
    mystring = "foo was null";
else
    mystring = foo;


如果条件是计算结果的函数,那么使用三元运算符最终会调用函数两次(在计算结果为true的情况下).而使用?只会打电话一次.

84> Robert Durgi..:

#如果DEBUG预处理器指令.它对测试和调试很有用(虽然我通常更喜欢单元测试路线).

string customerName = null;
#if DEBUG
  customerName = "Bob"
#endif

如果Visual Studio设置为在"调试"模式下编译,它将只执行代码块.否则编译器将忽略代码块(并在Visual Studio中显示为灰色).


[条件("DEBUG")] - 标记的方法通常使代码更清晰,更易于阅读.
请注意,您可以定义任何符号,然后对该符号使用条件编译.默认情况下,DEBUG恰好会自动为您定义.

85> Mohammad Tay..:

我没有找到任何使用string.Join的人使用分隔符连接字符串.每个人都在写同样丑陋的for循环

var sb = new StringBuilder();
var count = list.Count();
for(int i = 0; i < count; i++)
{
  if (sb.Length > 0) sb.Append(seperator);
  sb.Append(list[i]);
}

return sb.ToString();

代替

return string.Join(separator, list.ToArray());


在.Net 4中,String.Join与IEnumerable一起使用,因此您不需要先转换为数组.

86> Jon Erickson..:
部分方法

Charlie Calvert在他的博客上解释了部分方法

Scott Cate在这里有一个不错的部分方法演示

    代码生成类(LINQ to SQL,EF)中的可扩展性点

    如果未实现,则不会编译到dll中(使用.NET Reflector检查)



87> Jakub Šturc..:

真与假的运营商是很奇怪的.

可以在这里找到更全面的例子.

编辑:有相关的问题C#中的false运算符有什么用呢?


已经使用C#5年了,从未见过真正的运算符过载.有意义,因为你可以重载算术和相等运算符.谢谢!

88> Pop Catalin..:

C#中有一些与TypedReference未记录类相关的隐藏关键字和功能.以下关键字未记录:

__makeref

__reftype

__refvalue

__arglist

使用示例:

// Create a typed reference
int i = 1;
TypedReference tr1 = __makeref(i);
// Get the type of a typed reference
Type t = __reftype(tr1);
// Get the value of a typed referece
int j = __refvalue(tr1, int); 
// Create a method that accepts and arbitrary number of typed references
void SomeMethod(__arglist) { ...
// Call the method
int x = 1;
string y = "Foo";
Object o = new Object();
SomeMethod(__arglist(x,y,o));
// And finally iterate over method parameters
void SomeMethod(__arglist) {
    ArgIterator ai = new ArgIterator(__arglist);
while(ai.GetRemainingCount() >0)
{
      TypedReference tr = ai.GetNextArg();
      Console.WriteLine(TypedReference.ToObject(tr));
}}


是的,使用它们是有风险的,这些隐藏的关键字是在泛型之前引入互操作,P/Invoke更快,因为这些功能可以让你避免装箱/取消装箱值类型.

89> Roman Boiko..:

我发现只有少数开发人员知道这个功能.

如果您需要一个通过某个接口(通过此值类型实现)使用值类型变量的方法,则在方法调用期间很容易避免装箱.

示例代码:

using System;
using System.Collections;

interface IFoo {
    void Foo();
}
struct MyStructure : IFoo {
    public void Foo() {
    }
}
public static class Program {
    static void MethodDoesNotBoxArguments(T t) where T : IFoo {
        t.Foo();
    }
    static void Main(string[] args) {
        MyStructure s = new MyStructure();
        MethodThatDoesNotBoxArguments(s);
    }
}

IL代码不包含任何框指令:

.method private hidebysig static void  MethodDoesNotBoxArguments<(IFoo) T>(!!T t) cil managed
{
  // Code size       14 (0xe)
  .maxstack  8
  IL_0000:  ldarga.s   t
  IL_0002:  constrained. !!T
  IL_0008:  callvirt   instance void IFoo::Foo()
  IL_000d:  ret
} // end of method Program::MethodDoesNotBoxArguments

.method private hidebysig static void  Main(string[] args) cil managed
{
  .entrypoint
  // Code size       15 (0xf)
  .maxstack  1
  .locals init ([0] valuetype MyStructure s)
  IL_0000:  ldloca.s   s
  IL_0002:  initobj    MyStructure
  IL_0008:  ldloc.0
  IL_0009:  call       void Program::MethodDoesNotBoxArguments(!!0)
  IL_000e:  ret
} // end of method Program::Main

参见Richter,J.CLR via C#,2nd edition,chapter 14:Interfaces,section about Generics and Interface Constraints.

另见我对另一个问题的回答.


@AWC:任务是将一些接口的实例传递给我们的方法.这样我们就可以在传递的实例上调用此接口的方法.像`void BoxingMethod(IFoo x)`这样的声明如果`x`是值类型则导致装箱.您的示例不允许调用接口方法.上面的代码允许没有装箱的这种调用

90> mgsloan..:

已经提到了所有凉爽的附近.不确定这个是否众所周知

C#property/field构造函数初始化:

var foo = new Rectangle() 
{ 
    Fill = new SolidColorBrush(c), 
    Width = 20, 
    Height = 20 
};

这将创建矩形,并设置列出的属性.

我注意到了一些有趣的东西 - 你可以在属性列表的末尾加一个逗号,而不会出现语法错误.所以这也是有效的:

var foo = new Rectangle() 
{ 
    Fill = new SolidColorBrush(c), 
    Width = 20, 
    Height = 20,
};


最后的逗号更容易摆弄价值:)
你也不需要Rectangle()中的()

91> Will Dean..:

基于这个主题应该被称为" 直到最近你还不知道关于C#的事情,尽管认为你已经知道了所有事情 ",我的个人特征是异步代表.

直到我读到Jeff Richter的C#/ CLR书(优秀的书,每个人都在读.NET)我不知道你可以用/ 调用任何代表.我倾向于做很多调用(我猜这很像是委托在内部做的事情),但是有时添加标准化的连接/会合模式可能非常有用.BeginInvokeEndInvokeThreadPool.QueueUserWorkItemBeginInvoke



92> open-collar..:

有几个人提到使用积木,但我认为它们比人们意识到的要有用得多.把它们想象成穷人的AOP工具.我有许多简单的对象,它们在构造函数中捕获状态,然后在Dispose()方法中恢复它.这允许我将一个功能包装在一个使用块中,并确保在最后恢复状态.例如:

using(new CursorState(this, BusyCursor));
{
    // Do stuff
}

CursorState捕获表单使用的当前游标,然后设置表单以使用提供的游标.最后它恢复原始光标.我做了很多这样的事情,例如在刷新之前捕获网格上的选择和当前行等等.



93> Bill Barry..:

关于事件处理程序的另一个注意事项:您可以像这样简单地创建一个raise extension方法:

public static class EventExtensions {
    public static void Raise(this EventHandler @event, 
                                object sender, T args) where T : EventArgs {
        if(@event!= null) {
            @event(sender, args);
        }
    }
}

然后你可以用它来举起事件:

public class MyImportantThing {
    public event EventHandler SomethingHappens;
    ...
    public void Bleh() {
        SomethingHappens.Raise(this, new MyImportantEventEventArgs { X=true });
    }
}

该方法具有强制执行编码标准(使用EventHandler<>)的附加优点.

一遍又一遍地写出相同的功能是没有意义的.也许C#的下一个版本最终会有一个InlineAttribute可以放在扩展方法上,并且会使编译器内联方法定义(这将使这种方式接近标准,并且最快).

编辑:根据注释删除扩展方法中的临时变量



94> Joel Coehoor..:

我参加这个派对已经很晚了,所以我的第一选择已经开始了.但我没有看到有人提到这个宝石:

.NET Framework的并行扩展

它有一些东西,比如使用Parallel.ForEach替换Parallel.For或foreach


并行示例:
在您看来,一秒钟内可以创建多少个CLR对象? 在此输入图像描述
见下面的例子:

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;

namespace ObjectInitSpeedTest
{
   class Program
   {
       //Note: don't forget to build it in Release mode.
       static void Main()
       {
           normalSpeedTest();           
           parallelSpeedTest();

           Console.ForegroundColor = ConsoleColor.White;
           Console.WriteLine("Press a key ...");
           Console.ReadKey();
       }

       private static void parallelSpeedTest()
       {
           Console.ForegroundColor = ConsoleColor.Yellow;
           Console.WriteLine("parallelSpeedTest");

           long totalObjectsCreated = 0;
           long totalElapsedTime = 0;

           var tasks = new List();
           var processorCount = Environment.ProcessorCount;

           Console.WriteLine("Running on {0} cores", processorCount);

           for (var t = 0; t < processorCount; t++)
           {
               tasks.Add(Task.Factory.StartNew(
               () =>
               {
                   const int reps = 1000000000;
                   var sp = Stopwatch.StartNew();
                   for (var j = 0; j < reps; ++j)
                   {
                       new object();
                   }
                   sp.Stop();

                   Interlocked.Add(ref totalObjectsCreated, reps);
                   Interlocked.Add(ref totalElapsedTime, sp.ElapsedMilliseconds);
               }
               ));
           }

           // let's complete all the tasks
           Task.WaitAll(tasks.ToArray());

           Console.WriteLine("Created {0:N} objects in 1 sec\n", (totalObjectsCreated / (totalElapsedTime / processorCount)) * 1000);
       }

       private static void normalSpeedTest()
       {
           Console.ForegroundColor = ConsoleColor.Green;
           Console.WriteLine("normalSpeedTest");

           const int reps = 1000000000;
           var sp = Stopwatch.StartNew();
           sp.Start();
           for (var j = 0; j < reps; ++j)
           {
               new object();
           }
           sp.Stop();

           Console.WriteLine("Created {0:N} objects in 1 sec\n", (reps / sp.ElapsedMilliseconds) * 1000);
       }
   }
}



95> 小智..:

我喜欢的一个很棒的类是System.Xml.XmlConvert可以用来从xml标签读取值.特别是,如果我从xml属性或元素中读取布尔值,我会使用

bool myFlag  = System.Xml.XmlConvert.ToBoolean(myAttribute.Value);

注意:由于xml中的boolean类型除了"true"和"false"之外还接受1和0作为有效值,因此在这种情况下使用字符串比较容易出错.



96> Dave Van den..:

Atrribute目标

每个人都看过一个.基本上,当你看到这个:

[assembly: ComVisible(false)]

该属性的"assembly:"部分是目标.在这种情况下,属性将应用于程序集,但还有其他属性:

[return: SomeAttr]
int Method3() { return 0; } 

在此示例中,该属性应用于返回值.



97> rikoe..:

对于发布这么晚的道歉,我是Stack Overflow的新手,所以错过了之前的机会.

我发现这EventHandler是一个未充分利用的框架的一个很棒的特性.

我遇到的大多数C#开发人员在定义自定义事件时仍定义自定义事件处理程序委托,这根本就不再需要了.

代替:

public delegate void MyCustomEventHandler(object sender, MyCustomEventArgs e);

public class MyCustomEventClass 
{
    public event MyCustomEventHandler MyCustomEvent;
}

你可以走了:

public class MyCustomEventClass 
{
    public event EventHandler MyCustomEvent;
}

这更简洁,而且你不会陷入是否将委托放在包含事件的类的.cs文件或EventArgs派生类的困境中.



98> ntziolis..:

IObservable怎么样?

几乎每个人都知道IEnumerable,但他们的数学对偶似乎是未知的IObservable.也许是因为它在.NET 4中的新功能.

它所做的不是拉动信息(如可枚举的信息)而是将信息推送到可观察者的订户.

Rx扩展一起,它将改变我们处理事件的方式.只是想说明它是多么强大的检查很短的例子在这里.



99> Thomas Leves..:

好吧,这看起来很明显,但我想提一下Object.Equals方法(静态方法,有两个参数).

我很确定很多人甚至都不知道它,或者忘记了它,但在某些情况下它确实有用.例如,当您想比较两个对象是否相等时,不知道它们是否为空.你写了多少次这样的东西:

if ((x == y) || ((x != null && y != null) && x.Equals(y)))
{
    ...
}

当你可以写:

if (Object.Equals(x, y))
{
    ...
}

(Object.Equals实际上与第一个代码示例完全相同)



100> Dann..:
string.Empty

我知道这不是幻想(荒唐奇怪),但我一直用它来代替"".

它会被隐藏起来,直到有人告诉你它在那里.


@Arnos:这不是为了做空; 它是关于可维护性的:在你编写一些代码2个月后理解某些东西的含义.而不是想知道""实际意味着""(和忘记空间)或空字符串.`String.Empty`更清晰.这通常适用于`.Empty`模式:您可以在更多类型中看到它.
如果您对框架有所了解,则不完全隐藏.
这是你得到宗教争论的事情之一:`string.Empty` vs`""` - 我个人觉得后者更容易阅读,它与编译的代码没有什么不同.
我觉得http://blogs.msdn.com/b/ericlippert/archive/2009/09/28/string-interning-and-string-empty.aspx很有意思.它指出了一种情况,````和`string.Empty`在`=='比较期间不会有相同的行为.
String.Empty是.NET,而不是C#.可以从.NET框架上的任何语法访问它.
@Arnis:`string.Empty`更'正确'.但是作为参考,`.Empty`并不是一个稀疏使用的值,大多数值类型实现它,并且Microsoft的指南鼓励它的使用(事实上,常见值的静态版本,`MinValue`和`MaxValue`是另外两个常见的值).当可以使用相同的实例时,它可以防止不必要的重复值类型的创建(不可变值类型).
尽可能接近隐藏的任何标志指向它.例如,StyleCop会告诉您使用它:警告2 SA1122:使用string.Empty而不是"".

101> John Sheehan..:

我看到很多人复制了它的功能Nullable.GetValueOrDefault(T).



102> Mark Cidade..:

C#3.0的LINQ查询理解是一个完整的monadic理解 Haskell(实际上它们是由Haskell的一个设计者设计的).它们适用于"LINQ模式"之后的任何泛型类型,并允许您以纯monadic函数样式编写,这意味着所有变量都是不可变的(就好像您使用的唯一变量是IDisposables和IEnumerables在使用foreach声明).这有助于将变量声明保持在接近它们使用的位置,并确保明确声明所有副作用(如果有的话).

 interface IFoo
  { T Bar {get;}
  }

 class MyFoo : IFoo 
  { public MyFoo(T t) {Bar = t;}
    public T Bar {get; private set;} 
  }

 static class Foo 
  { public static IFoo ToFoo(this T t) {return new MyFoo(t);}

    public static void Do(this T t, Action a) { a(t);}

    public static IFoo Select(this IFoo foo, Func f) 
     { return f(foo.Bar).ToFoo();
     }
  }

 /* ... */

 using (var file = File.OpenRead("objc.h"))
 { var x = from f in file.ToFoo()
           let s = new Scanner(f)
           let p = new Parser {scanner = s}
           select p.Parse();

   x.Do(p => 
    { /* drop into imperative code to handle file 
         in Foo monad if necessary */      
    });

 }



103> Steve Dunn..:

不是真的隐藏,但有用.当你有一个enumflags,你可以使用左移位,使事情更加清楚.例如

[Flags]
public enum ErrorTypes {
    None              = 0,
    MissingPassword   = 1 << 0,
    MissingUsername   = 1 << 1,
    PasswordIncorrect = 1 << 2 
}


@ AOIKarasu- C#本身适用于不会被低级语言困扰的懒惰.较低级别的语言适用于无法使用Assembler的懒惰语言.汇编程序适用于不能打字输入二进制文件的懒惰人.打字是为了不能在硬盘上蚀刻小点的懒惰.硬盘是为了不会打卡的懒人.打卡是为了懒散而无法在纸上划线的人.纸张适用于不能在石碑上蚀刻的懒惰纸.我有各种各样的懒惰!:)第9位仍然更容易读作"1 << 9"而不是512. YMMV!
有意思,但任何人都没有立即认识到模式0,1,2,4,8 ... 16384,32768 ...可能不应该读代码,而且几乎肯定不会知道1 << 2 == 4.
FlagsAttribute本身应该让人意识到枚举是一个小字段.枚举定义中的IMO移位不是为了可读性,而是为了懒惰,他们不记得两个值的强大功能;)
你能解释一下吗?我不确定我是如何工作或它做的
它只是移位数字的二进制表示中的位,0001 << 1变为0010,0001 << 2变为0100,0001 << 3变为1000
你要离开一个,因为1 << 1是2,你的第一个标志应该是1 << 0.

104> Peter Lillev..:

我最喜欢的属性:InternalsVisibleTo

在装配级别,您可以声明另一个装配可以看到您的内部.出于测试目的,这绝对是美妙的.

将它粘贴在AssemblyInfo.cs或同等版本中,您的测试程序集就可以完全访问需要测试的所有内部资源.

[assembly: InternalsVisibleTo("MyLibrary.Test, PublicKey=0024...5c042cb")]

如您所见,测试程序集必须具有强名称才能获得被测程序集的信任.

提供.Net Framework 2.0 +,Compact Framework 2.0+和XNA Framework 1.0+.


是的,非常适合测试组件......而且只测试组件.对?;)

105> Nathan Lee..:

我喜欢使用@字符进行SQL查询.它使sql保持良好和格式化,而不必用字符串分隔符包围每一行.

string sql = @"SELECT firstname, lastname, email
               FROM users
               WHERE username = @username AND password = @password";


另一个问题是你在代码中编写SQL :(
对此的一个小抱怨(在这种情况下)是用于缩进的空格和换行符最终在字符串中.通常不是一个问题,而是一个需要注意的问题.
SQL使用参数.除了SQL本身是硬编码之外,我没有看到任何问题.

106> Jakub Šturc..:

在外部别名关键字来引用具有相同的完全限定的类型名称组件的两个版本.



107> Keith Adler..:

您可以使用{ }括号限制变量的寿命和范围.

{
    string test2 = "3";
    Console.Write(test2);
}

Console.Write(test2); //compile error

test2 只生活在括号内.


C++也是如此.

108> 小智..:

需要返回一个空的IEnumerable吗?

public IEnumerable GetEnumerator(){
  yield break;
}


已经在BCL`System.Linq.Enumerable.Empty ()`中
这个对我的口味有点不透明,我更喜欢chakrit的解决方案.
@chak哪个是`return new T [0];`的包装器.有很多方法可以做到这一点.这只是一个.但这是一个有趣的...

109> Rinat Abdull..:

能够使用LINQ表达式执行强类型反射:

static void Main(string[] args)
{
  var domain = "matrix";
  Check(() => domain);
  Console.ReadLine();
}

static void Check(Expression> expr)
{
  var body = ((MemberExpression)expr.Body);
  Console.WriteLine("Name is: {0}", body.Member.Name);
  Console.WriteLine("Value is: {0}", ((FieldInfo)body.Member)
   .GetValue(((ConstantExpression)body.Expression).Value));
}

// output:
// Name is: 'domain'
// Value is: 'matrix'

有关更多详细信息,请参阅如何在C#中找出变量或参数名称?



110> FFire..:

您可以在Enum中存储颜色.

public enum MyEnumColors : uint
{
    Normal          = 0xFF9F9F9F,
    Active          = 0xFF8EA98A,
    Error           = 0xFFFF0000
}


我认为FFire试图引起注意这样一个事实,你可以为枚举指定基类型(在本例中为uint)
是的,但是为了什么?为什么不创建强类型的静态类属性呢?也可以滥用字符串来存储任意数据blob,而不是像BASIC中常用的那样使用类.

111> Lars Mæhlum..:

我经常遇到将通用参数对象持久保存到基类中的视图状态的需要.

public abstract class BaseListControl
                 : UserControl 
                 where ListType : BaseListType
                 && ParameterType : BaseParameterType, new
{

    private const string viewStateFilterKey = "FilterKey";

    protected ParameterType Filters
    {
        get
        {
            if (ViewState[viewStateFilterKey] == null)
                ViewState[viewStateFilterKey]= new ParameterType();

            return ViewState[viewStateFilterKey] as ParameterType;
        }
        set
        {
            ViewState[viewStateFilterKey] = value;
        }
    }

}

用法:

private void SomeEventHappened(object sender, EventArgs e)
{
    Filters.SomeValue = SomeControl.SelectedValue;
}

private void TimeToFetchSomeData()
{
    GridView.DataSource = Repository.GetList(Filters);
}

这个关于"where ParameterType:BaseParameterType,new"的小技巧是让它真正起作用的原因.

在我的基类中使用此属性,我可以自动处理分页,设置过滤器值以过滤网格视图,使排序变得非常简单等.

我只是说仿制药可以成为一个非常强大的野兽.



112> Martin Clark..:

如何在枚举上使用FlagsAttribute?它允许您执行按位操作...让我永远地了解如何在.NET中进行按位操作.


这实际上非常危险 - 它对分配的值没有任何影响 - 它纯粹是一个标记属性来表示你的意图,所以如果你没有明确地声明你的枚举值为2的幂,那么你会认为你有一个按位枚举,但你不会真的......
我认为你可以对任何枚举进行按位运算,标志只影响ToString()方法

113> Tor Haugen..:

您可以在C#名称中使用任何Unicode字符,例如:

public class MyClass
{
    public string Hårføner()
    {
        return "Yes, it works!";
    }
}

您甚至可以使用Unicode转义.这个相当于上面的:

public class MyClass
{
    public string H\u00e5rføner()
    {
        return "Yes, it (still) works!";
    }
}


嗯,是的,让我们将英文BCL标识符和关键字与非英文标识符混合使用.现在来自其他国家的人不能使用你的代码而没有Intellisense:P;)不可以.只是因为能够使用任何角色,但它没有真正的好处.

114> 小智..:

您可以使用较少的键入来添加和删除委托.

通常的方式:

handler += new EventHandler(func);

减少打字方式:

handler += func;


一直看到...只是让我的手痒:)另外,如果你在VS中键入+ =然后[TAB] [TAB]生成一个事件处理程序,代理类型仍然插入...有点烦人.

115> Edison Chuan..:

使用带有FlagAttribute和enum的"〜"运算符
有时我们会使用带有枚举的Flag属性对枚举执行按位操作.

 [Flags]
 public enum Colors
 {
    None  = 0,
    Red   = 1,
    Blue  = 2,
    White = 4,
    Black = 8,
    Green = 16,
    All   = 31 //It seems pretty bad...
 }

请注意,枚举中选项"All"的值非常奇怪.
而不是我们可以使用带有标记枚举的"〜"运算符.

 [Flags]
 public enum Colors
 {
    None  = 0,
    Red   = 1,
    Blue  = 2,
    White = 4,
    Black = 8,
    Green = 16,
    All   = ~0 //much better now. that mean 0xffffffff in default.
 }


请记住,它是一个标记的枚举.所以在这种情况下,"All"等于(Red&Blue&White&Black&Green),那么它也等于(00001&00010&00100&01000&10000)并且等于11111并且等于31.数字32应该是100000但是11111.
我更喜欢拼写出来`All = Red | 蓝色| 白色| 黑色| 绿色`和例如`Dark = Blue | 黑色,光=全部和〜暗

116> Incognito..:

也很有用,但不常用:约束执行区域.

BCL团队博客引用:

存在约束执行区域(CER)以帮助开发人员编写代码以保持一致性.CLR不保证开发人员的代码是正确的,但CLR确实将所有运行时引发的故障点(即异步异常)提升到代码运行之前或完成之后.结合对开发人员可以放入CER的限制,这些是对代码是否执行提供强有力保证的有用方法.CER正在热切地准备,这意味着当我们看到一个时,我们将急切地JIT在其静态可发现的调用图中找到的任何代码.如果CLR的主机关心堆栈溢出,我们也将探测一些堆栈空间(尽管可能没有足够的堆栈空间用于任何方法*).

在以原子方式对数据结构的多个字段进行编辑时,它非常有用.因此,在对象上进行事务是有帮助的.

此外CriticalFinalizerObject似乎被隐藏(至少谁不写不安全的代码).CriticalFinalizerObject保证垃圾收集将执行终结器.在分配时,终结器及其调用图是预先准备的.



117> Incognito..:

固定的声明

此语句可防止垃圾回收器重定位可移动变量.Fixed也可用于创建固定大小的缓冲区.

fixed语句设置一个指向托管变量的指针,并在执行语句时设置变量"pins".

stackalloc

stackalloc在堆栈上分配一块内存.


我认为这应该包括一个为什么/如何有用的例子

118> Andrew Burns..:

ConditionalAttribute

允许您告诉编译器在特定条件下(#define)省略对使用该属性标记的方法的调用.

省略方法调用的事实也意味着不评估其参数.这非常方便,它允许您在Debug.Assert()中调用昂贵的验证函数,而不用担心它们会减慢您的发布版本.



119> Mihai Lazar..:

我在Stack Overflow上只学到的一个功能是能够在返回参数上设置属性.

[AttributeUsage( AttributeTargets.ReturnValue )]
public class CuriosityAttribute:Attribute
{
}

public class Bar
{
    [return: Curiosity]
    public Bar ReturnANewBar()
    {
        return new Bar();
    }
}

这对我来说真的是一个隐藏的功能:-)


它将Curiosity作为属性应用于返回的实例.

120> tsilb..:

标记我的终端区域......

#region stuff1
 #region stuff1a
 //...
 #endregion stuff1a
#endregion stuff1



121> codymanix..:

定义自定义属性时,可以将它们与[MyAttAttribute]或[MyAtt]一起使用.当两个着作都存在类时,就会发生编译错误.

@ special字符可用于区分它们:

[AttributeUsage(AttributeTargets.All)]
public class X: Attribute
{}

[AttributeUsage(AttributeTargets.All)]
public class XAttribute: Attribute
{}

[X]      // Error: ambiguity
class Class1 {}

[XAttribute]   // Refers to XAttribute
class Class2 {}

[@X]      // Refers to X
class Class3 {}

[@XAttribute]   // Refers to XAttribute
class Class4 {}



122> Jehof..:

当一个类实现INotifyPropertyChanged并且您想要通知绑定系统(WPF,Silverlight等)时,对象(ViewModel)的多个绑定属性已更改,您可以使用nullString.Empty引发PropertyChanged-Event .

这在MSDN中有记录,但代码示例和文章通常不能解释这种可能性.我发现它非常有用.

public class BoundObject : INotifyPropertyChanged {

    private int _value;
    private string _text;

    public event PropertyChangedEventHandler PropertyChanged;

    public int Value {
        get {
            return _value;
        }
        set {
            if (_value != value) {
                _value = value;
                OnPropertyChanged("Value");
            }
        }
    }

    public string Text {
        get {
            return _text;
        }
        set {
            if (_text != value) {
                _text = value;
                OnPropertyChanged("Text");
            }
        }
    }

    public void Init(){
        _text = "InitialValue";
        _value = 1;
        OnPropertyChanged(string.Empty);
    }

    public void Reset() {
        _text = "DefaultValue";
        _value = 0;
        OnPropertyChanged(string.Empty);
    }

    private void OnPropertyChanged(string propertyName) {
        PropertyChangedEventArgs e = new PropertyChangedEventArgs(propertyName);

        if (PropertyChanged != null) {
            PropertyChanged(this, e);
        }
    }
}



123> Ozan..:

您可以在一对方括号中放置几个​​属性:

    [OperationContract, ServiceKnownType(typeof(Prism)), ServiceKnownType(typeof(Cuboid))]
    Shape GetShape();



124> t3rse..:

Lambda表达式

Func add = (a, b) => (a + b);

模糊的字符串格式

Console.WriteLine("{0:D10}", 2); // 0000000002

Dictionary dict = new Dictionary { 
    {"David", "C#"}, 
    {"Johann", "Perl"}, 
    {"Morgan", "Python"}
};

Console.WriteLine( "{0,10} {1, 10}", "Programmer", "Language" );

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

foreach (string key in dict.Keys)
{
    Console.WriteLine( "{0, 10} {1, 10}", key, dict[key] );             
}



125> AlexCuse..:

直到最近我才开始非常欣赏"使用"块.他们让事情变得更加整洁:)



126> 小智..:

怎么样使用这个:

#if DEBUG
            Console.Write("Debugging");
#else
            Console.Write("Final");
#endif

当您使用DEBUG定义编译解决方案时,它将输出"Debugging".

如果您的编译设置为Release,它将写入"Final".



127> Andrew Laver..:

FlagsAttribute,使用枚举制作位掩码时的一个小但很好的功能:

[Flags]
public enum ConfigOptions
{
    None    = 0,
    A       = 1 << 0,
    B       = 1 << 1,
    Both    = A | B
}

Console.WriteLine( ConfigOptions.A.ToString() );
Console.WriteLine( ConfigOptions.Both.ToString() );
// Will print:
// A
// A, B



128> Brian Surowi..:

我正在成为扩展方法的忠实粉丝,因为它们可以为现有代码或无法编辑的代码添加许多想要的功能.我最喜欢的一个是我现在所做的一切是string.IsNullOrEmpty()

public static class Strings
{
    public static bool IsNullOrEmpty(this string value)
    {
        return string.IsNullOrEmpty(value);
    }
}

这使您可以像这样缩短代码

var input = Console.ReadLine();
if (input.IsNullOrEmpty())
{
    Console.WriteLine("try again");
}


我现在正在2个项目中使用它进行工作以及许多个人项目.我将IsNullOrEmpty方法放在一个名为Strings的类中,并将其他扩展方法放在字符串类中.我没有遇到任何问题,编译器告诉我方法名称无效,并且已经在我的代码中使用它3或4个月了.
@John:我试过Brian的代码,它有效.
@John我认为它有效,因为原始的IsNullOrEmpty采用一个参数,而不是这个参数.所以它只是超载.

129> thr..:
工厂方法的类型推断

我不知道这是否已经发布(我扫描了第一篇文章,找不到它).

最好用一个例子来说明,假设你有这个类(模拟一个元组),试图展示使这成为可能的所有语言特征,我将逐步完成它.

public class Tuple : Tuple
{
    public readonly V1 v1;
    public readonly V2 v2;

    public Tuple(V1 v1, V2 v2)
    {
      this.v1 = v1;
      this.v2 = v2;
    }
}

每个人都知道如何创建它的实例,例如:

Tuple tup = new Tuple(1, "Hello, World!");

不完全是火箭科学,现在我们当然可以将变量的类型声明更改为var,如下所示:

var tup = new Tuple(1, "Hello, World!");

仍然众所周知,这里有一个带有类型参数的静态方法,每个人都应该熟悉:

public static void Create()
{
    // stuff
}

再一次常识,这就是这样做的:

Create();

大多数人不知道的是,如果泛型方法的参数包含它所需的所有类型,则可以推断它们,例如:

public static void Create(T1 a, T2 b)
{
    // stuff
}

这两个电话是相同的:

Create(1.0f, "test");
Create(1.0f, "test");

因为T1和T2是从您传递的参数推断出来的.将这些知识与var关键字相结合,我们可以通过添加静态方法的第二个静态类,例如:

public abstract class Tuple
{
    public static Tuple Create(V1 v1, V2 v2)
    {
        return new Tuple(v1, v2);
    }
}

达到这个效果:

var tup = Tuple.Create(1, "Hello, World!");

这意味着:变量"tup"的类型,"Create"的类型参数和"Create"的返回值都是从作为参数传递给Create的类型推断出来的.

完整代码看起来像这样:

public abstract class Tuple
{
    public static Tuple Create(V1 v1, V2 v2)
    {
        return new Tuple(v1, v2);
    }
}

public class Tuple : Tuple
{
    public readonly V1 v1;
    public readonly V2 v2;

    public Tuple(V1 v1, V2 v2)
    {
        this.v1 = v1;
        this.v2 = v2;
    }
}

// Example usage:
var tup = Tuple.Create(1, "test");

它为您提供完全类型推断的工厂方法!



130> cllpse..:

使用LINQ轻松实现眼睛/浓缩ORM映射

考虑一下这个表:

[MessageId] INT,
[MessageText] NVARCHAR(MAX)
[MessageDate] DATETIME

......而这个结构:

struct Message
{
    Int32 Id;
    String Text;
    DateTime Date;
}



而不是做以下事情:

List messages = new List();

foreach (row in DataTable.Rows)
{
    var message = new Message
    {
        Id = Convert.ToInt32(row["MessageId"]),
        Text = Convert.ToString(row["MessageText"]),
        Date = Convert.ToDateTime(row["MessageDate"])
    };

    messages.Add(message);
}

你可以使用LINQ,用更少的代码行做同样的事情,在我看来; 更多风格.像这样:

var messages = DataTable.AsEnumerable().Select(r => new Message
{
    Id = Convert.ToInt32(r["MessageId"]),
    Text = Convert.ToString(r["MessageText"]),
    Date = Convert.ToDateTime(r["MessageDate"])
}).ToList();

这种方法可以嵌套,就像循环一样.


+1大大提高了可读性.我认为新代码在眼睛上更容易.虽然今天普通的C#程序员仍然在程序上进行编程,但这种情况会很快发生变化.我发现当你向大多数程序程序员展示他们立即理解的LINQ版本并说出"哇!"之类的东西.并想知道他们如何自己使用它.
你甚至可以使用Field (name)扩展:`r.Field ("MessageId")`(我希望我不必知道)
这是一个有趣的方法,但我不相信它在眼睛上更容易.在我看来,对于普通程序员来说,理解起来并不容易.

131> Alex Lyman..:

通过下降switch- caseS可通过不具有代码在一个来实现case(见case 0),或者使用特殊的goto case(见case 1)或goto default(见case 2)形式:

switch (/*...*/) {
    case 0: // shares the exact same code as case 1
    case 1:
        // do something
        goto case 2;
    case 2:
        // do something else
        goto default;
    default:
        // do something entirely different
        break;
}


我认为在一个开关中只放置一个goto _is_可接受.

132> Cohen..:

我错过了很长一段时间的东西:你可以比较字符串

"string".equals("String", StringComparison.InvariantCultureIgnoreCase)

而不是做:

"string".ToLower() == "String".ToLower();


Actualy,StringComparison.OrdinalIgnoreCase应该在很多情况下使用.
微软也针对大写比较进行了优化,因此ToUppper在旧方式上会更好.
我知道这应该是正确的方法,但我对enum本身的冗长感到恼火.

133> tuinstoel..:

如果方法参数实现了两个接口,则可以使用泛型来检查(编译时):

interface IPropA 
{
    string PropA { get; set; } 
}

interface IPropB 
{
    string PropB { get; set; }
}

class TestClass 
{
    void DoSomething(T t) where T : IPropA, IPropB 
    {
        MessageBox.Show(t.PropA);
        MessageBox.Show(t.PropB);
    }
}

与从基类和接口继承的参数相同.



134> Paul Ruane..:

我能想到的一对夫妇:

[field: NonSerialized()]
public EventHandler event SomeEvent;

这可以防止事件被序列化.'field:'表示该属性应该应用于事件的支持字段.

另一个鲜为人知的功能是覆盖add/remove事件处理程序:

public event EventHandler SomeEvent
{
    add
    {
        // ...
    }

    remove
    {
        // ...
    }
}



135> Duncan Smart..:

我喜欢这样的事实:我可以在普通的旧版.NET 2.0上使用LINQ来对象(即不需要在任何地方安装.NET 3.5).您所需要的只是所有查询运算符Extension方法的实现 - 请参阅LINQBridge



136> Benjol..:

    我还无法发表评论,但请注意,默认情况下,Visual Studio 2008会自动切换属性,因此在这种情况下不再需要DebuggerStepThrough属性.

    另外,我没有注意到有人展示如何声明一个无参数的lambda(对于实现Action <>很有用)

    () => DoSomething(x);

你还应该阅读关闭 - 我不够聪明,无法正确解释它们.但基本上它意味着编译器会做一些聪明的事情,以便即使在创建lambda之后它超出范围,代码行中的x仍然可以工作.

    我最近也发现你可以假装忽略一个lambda参数:

    (e, _) => DoSomething(e)

它并不是真的忽略它,只是_是一个有效的标识符.所以你不能忽略这两个参数,但我认为这是一种巧妙的方式来表明我们不关心那个参数(通常是EventArgs .Empty).



137> Flory..:

在声明的类和一个或多个任意类之间存在用于执行implicitexplicit用户定义的类型转换的运算符.的implicit操作者有效地允许重载assignement操作者,这是在语言可能的,诸如C++但不C#的模拟.

它似乎不是经常出现的功能,但实际上它在LINQ to XML(System.Xml.Linq)库中使用,您可以在其中隐式地将字符串转换为XName对象.例:

XName tagName = "x:Name";

我在本文中发现了有关如何在C#中模拟多重继承的这一特性.



138> Phillip Ngan..:

委托语法已经在C#的连续版本中发展,但我仍然发现它们很难记住.幸运的是Action<>,Func<>代表们很容易记住.

例如:

Action 是一个委托方法,它接受一个int参数并返回void.

Func 是一个委托方法,不带参数并返回一个int.

Func 是一个委托方法,它接受一个int参数并返回一个bool.

这些功能是在.NET框架的3.5版本中引入的.



139> Wim Coenen..:

可以调用扩展方法null; 这不会导致NullReferenceException抛出.

示例应用程序:您可以为ToString()被调用定义一个替代方法ToStringOrEmpty(),它将在调用时返回空字符串null.



140> Binoj Antony..:

要调用基类构造函数,只需将base()与构造函数内联.
要调用基类方法,只需将base.MethodName()放在派生类方法中即可

class ClassA 
{
  public ClassA(int a)
  {
    //Do something
  }

  public void Method1()
  {
     //Do Something
  }
}

class ClassB : ClassA
{
  public ClassB(int a) : base(a) // calling the base class constructor
  {
    //Do something
  }

  public void Method2()
  {
    base.Method1();               // calling the base class method
  }
}

当然,你只需说出就可以调用基类的方法 base.MethodName()



141> Moran Helman..:

TrueForAll方法List:

List s = new List { 6, 1, 2 };

bool a = s.TrueForAll(p => p > 0);



142> nsantorello..:

很少有人知道的一件事是一些C#引入的预处理器指令.您可以使用#error This is an error.生成编译器错误和#warning This is a warning.

当我使用自上而下的方法开发作为"待办事项"列表时,我通常使用这些.我会#error Implement this function,或者#warning Eventually implement this corner case作为提醒.


你能不能只使用TODO:Visual Studio中的注释?http://dotnetperls.com/todo-comments-visual-studio

143> Titian Cerni..:

不确定这个是否已被提及,但ThreadStatic属性是一个非常有用的属性.这使静态字段仅为当前线程静态.

[ThreadStatic]
private static int _ThreadStaticInteger;

你不应该包含一个初始值设定项,因为它只对整个应用程序执行一次,你最好使字段可以为空,并在使用之前检查值是否为null.

ASP.NET应用程序线程的另一个用途是重用,因此如果修改该值,它最终可能会被用于另一个页面请求.

我仍然发现这有用几次.例如,在创建自定义事务类时:

using (DbTransaction tran = new DbTransaction())
{
    DoQuery("...");
    DoQuery("...");    
}

DbTransaction构造函数将ThreadStatic字段设置为self,并在dispose方法中将其重置为null.DoQuery检查静态字段,如果!= null使用当前事务,否则默认为其他事务.我们避免必须将事务传递给每个方法,而且它可以很容易地包装其他方法,这些方法原本不是用于事务中的事务...

只需一次使用:)



144> Mark Seemann..:

Or赋值运算符是相当不错的.你可以这样写:

x |= y

而不是这个:

x = x | y

如果你有一个变量或属性(这通常是实际x启动了作为例子)false,但你想改变它的一些其他的布尔变量/属性的值,只有当其他值true.



145> jpierson..:

嵌套类可以访问外部类的私有成员.

public class Outer
{
    private int Value { get; set; }

    public class Inner
    {
        protected void ModifyOuterMember(Outer outer, int value)
        {
            outer.Value = value;
        }
    }
}

现在,与上述功能一起,您也可以从嵌套类继承,就像它们是顶级类一样,如下所示.

public class Cheater : Outer.Inner
{
    protected void MakeValue5(Outer outer)
    {
        ModifyOuterMember(outer, 5);
    }
}

这些功能允许一些有趣的可能性,只要通过隐藏的类提供对特定成员的访问.



146> Dariusz..:

您可以使用以下方法更改舍入方案:

var value = -0.5;
var value2 = 0.5;
var value3 = 1.4;

Console.WriteLine( Math.Round(value, MidpointRounding.AwayFromZero) ); //out: -1
Console.WriteLine(Math.Round(value2, MidpointRounding.AwayFromZero)); //out: 1
Console.WriteLine(Math.Round(value3, MidpointRounding.ToEven)); //out: 1



147> 小智..:

如果您希望在调试和释放模式之间使用不同的行为,那么预处理器指令可能很有用.

http://msdn.microsoft.com/en-us/library/ed8yd1ha.aspx



148> axel_c..:
System.Diagnostics.Debug.Assert (false);

将触发弹出窗口并允许您在执行期间将调试器附加到正在运行的.NET进程.由于某些原因您无法直接调试ASP.NET应用程序时非常有用.


@Maslow,no - Debug.Assert方法用[Conditional("DEBUG")]标记,这意味着在非DEBUG构建中删除对它的调用.除非使用DEBUG标志构建生产代码,否则在这种情况下......
Debugger.Break();
使用System.Diagnostics.Debugger.Launch()

149> dariom..:

字符串实习.这是我尚未见过的讨论.它有点模糊,但在某些条件下它可能是有用的.

CLR保留一个对文字字符串的引用表(以及以编程方式实现的字符串).如果在代码中的多个位置使用相同的字符串,它将在表中存储一次.这可以减轻分配字符串所需的内存量.

您可以使用String.IsInterned(string)测试字符串是否被中断,并且您可以使用String.Intern(string)实习字符串.

注意: CLR可以在应用程序甚至AppDomain结束后保留​​对实习字符串的引用.有关详细信息,请参阅MSDN文档.



150> Richard Ever..:

IEnumerableSelectMany,它将列表列表展平为单个列表.假设我有一个清单Orders,每个Order清单都有一个清单LineItems.

我想知道LineItems售出的总数......

int totalItems = Orders.Select(o => o.LineItems).SelectMany(i => i).Sum();


int totalItems = Orders.SelectMany(o => o.LineItems).Sum();

151> Waleed Eissa..:

使用枚举.

将字符串转换为枚举:

enum MyEnum
{
    FirstValue,
    SecondValue,
    ThirdValue
}

string enumValueString = "FirstValue";
MyEnum val = (MyEnum)Enum.Parse(typeof(MyEnum), enumValueString, true)

我使用它从数据库中的设置表加载我的ASP.NET应用程序中的CacheItemPriority的值,以便我可以动态地控制缓存(以及其他设置),而无需关闭应用程序.

比较enum类型的变量时,不必转换为int:

MyEnum val = MyEnum.SecondValue;
if (val < MyEnum.ThirdValue)
{
    // Do something
}



152> Gorkem Pacac..:

我非常喜欢函数的隐式泛型参数.例如,如果您有:

public void DoStuff(T value);

而不是像这样调用它:

DoStuff(5);

您可以:

DoStuff(5);

它将从参数的类型中找出泛型类型.

如果您通过反射调用方法,则此方法无效.

我记得在Mono上有一些奇怪的问题.



153> Grokys..:

使用LINQ 测试IEnumerable 是否为空,请使用:

IEnumerable .Any();

起初,我正在使用(IEnumerable .Count()!= 0)...

这会不必要地导致枚举IEnumerable中的所有项目.

作为对此的改进,我继续使用(IEnumerable .FirstOrDefault()== null)...

哪个更好...

但IEnumerable .Any()是最简洁的,表现最好.



154> SemiColon..:

我很确定每个人都熟悉运算符重载,但也许有些不是.

class myClass
{
    private string myClassValue = "";

    public myClass(string myString)
    {
        myClassValue = myString;
    }

    public override string ToString()
    {
        return myClassValue;
    }

    public static myClass operator <<(myClass mc, int shiftLen)
    {
        string newString = "";
        for (int i = shiftLen; i < mc.myClassValue.Length; i++)
            newString += mc.myClassValue[i].ToString();
        mc.myClassValue = newString.ToString();
        return mc;
    }

    public static myClass operator >>(myClass mc, int shiftLen)
    {
        char[] newString = new char[shiftLen + mc.myClassValue.Length];

        for (int i = shiftLen; i < mc.myClassValue.Length; i++)
            newString[i] += mc.myClassValue[i - shiftLen];

        mc.myClassValue = new string(newString);
        return mc;
    }

    public static myClass operator +(myClass mc, string args)
    {
        if (args.Trim().Length > 1)
            mc.myClassValue += args;
        return mc;
    }

    public static myClass operator -(myClass mc, string args)
    {
        if (args.Trim().Length > 1)
        {
            Regex rgx = new Regex(args);
            mc.myClassValue = rgx.Replace(mc.myClassValue, "");
        }
        return mc;
    }
}

我认为能够使用<<和>>左右移动字符串或使用 - =删除一组遵循正则表达式模式的字符串是非常酷的

myClass tmpClass = new myClass("  HelloWorld123");
tmpClass -= @"World";
tmpClass <<= 2;
Console.WriteLine(tmpClass);


任何使用过拥有大量重载运算符的C++库的人都会告诉你,重载的运算符是邪恶的,邪恶的,邪恶的.只要写一个方法来做到这一点.
非常适合数学课程.例如,使矢量和矩阵的乘法非常容易读取,只需aVector = anotherVector*aMatrix; 而不是aVector = anotherVector.Multiply(aMatrix);
非常适合数学课程,正如@Sorskoot所说,但就是这样.对于几乎任何其他类,他们只是非常糟糕的方法名称.

155> johnc..:

不是C#特定的东西,但我是一个三元手术迷.

代替

if (boolean Condition)
{
    //Do Function
}
else
{
    //Do something else
}

你可以使用简洁

booleanCondtion ? true operation : false operation;

例如

代替

int value = param;
if (doubleValue)
{
    value *= 2;
}
else
{
    value *= 3;
}

你可以输入

int value = param * (tripleValue ? 3 : 2);

它确实有助于编写简洁的代码,但嵌套该死的东西可能是令人讨厌的,它们可以用于邪恶,但我喜欢这些小吸盘



156> Jan Banniste..:

你可以打开字符串!

switch(name)
{
  case "Dave":
    return true;
  case "Bob":
    return false;
  default:
    throw new ApplicationException();
}

非常便利!并且比一堆if-else语句更清晰



157> rein..:

而不是做这样的俗气:

Console.WriteLine("{0} item(s) found.", count);

我使用以下内联技巧:

Console.WriteLine("{0} item{1} found.", count, count==1 ? "" : "s");

当有一个项目时,这将显示"项目",或者当有更多(或更少)项目时,这将显示"项目".没有多少努力获得一点专业性.


我使用Pluralise(value,singularname,pluralname)方法来吐出整个"5项"字符串.这更具可读性,支持"鹅/鹅"复数化,并且在本地化方面更易于查找和处理.
是啊!国际化将是一个恐怖,但您可以执行以下操作:Console.WriteLine("{0} {1} found.",count,count == 1?"item":"items");

158> JoshL..:

在C#3.5中初始化Dictionary的表达式:

new Dictionary() {{"Testing", 123}, {"Test", 125}};



159> plaureano..:

C#允许您将属性setter方法添加到实现只读接口属性的具体类型,即使接口声明本身没有属性设置器.例如:

public interface IReadOnlyFoo
{
   object SomeReadOnlyProperty { get; }
}

具体类看起来像这样:

internal class Foo : IReadOnlyFoo
{
   public object SomeReadOnlyProperty { get; internal set; }
}

有趣的是,如果将它转换为IReadOnlyFoo接口,Foo类是不可变的:

// Create a Foo instance
Foo foo = new Foo();

// This statement is legal
foo.SomeReadOnlyProperty = 12345;

// Make Foo read only
IReadOnlyFoo readOnlyFoo = foo;

// This statement won't compile
readOnlyFoo.SomeReadOnlyProperty = 54321;



160> Matt Dotson..:

字典初始化器对于需要对某些数据进行硬编码的快速黑客攻击和单元测试总是很有用.

var dict = new Dictionary { { 10, "Hello" }, { 20, "World" } };



161> user287107..:

使用LINQ,可以根据参数创建新功能.如果你有一个很常见的微小函数,这是非常好的,但参数需要一些时间来计算.

    public Func RandomGenerator
    {
        get
        {
            var r = new Random();
            return () => { return r.Next(); };
        }
    }

    void SomeFunction()
    {
        var result1 = RandomGenerator();

        var x = RandomGenerator;
        var result2 = x();
    }


不,这是有趣的一点,一个随机对象刚刚创建

162> Serhat Ozgel..:

除了duncansmart的回复之外,还可以在Framework 2.0上使用扩展方法.只需ExtensionAttribute在System.Runtime.CompilerServices命名空间下添加一个类,就可以使用扩展方法(当然只能使用C#3.0).

namespace System.Runtime.CompilerServices
{
    public class ExtensionAttribute : Attribute
    { 
    }
}



163> Nelson Miran..:

您键入"prop",然后按[TAB]两次,它会为您的属性生成有用的代码,并可以加快您的输入速度.

我知道这可以在VS 2005中使用(我使用它),但我不知道以前的版本.


这是IDE的一个功能
ctor可用于创建构造函数

164> splattne..:

Object.ReferenceEquals方法

确定指定的Object实例是否是同一实例.

参数:

objA:System.Object - 要比较的第一个Object.

objB:System.Object - 要比较的第二个Object.

例:

 object o = null;
 object p = null;
 object q = new Object();

 Console.WriteLine(Object.ReferenceEquals(o, p));
 p = q;
 Console.WriteLine(Object.ReferenceEquals(p, q));
 Console.WriteLine(Object.ReferenceEquals(o, p));

与"=="和".Equals"的区别:

基本上,对象A的Equals()测试与对象B具有相同的内容.

System.Object.ReferenceEquals()方法始终比较引用.尽管类可以为等于运算符(下面)提供自己的行为,但是如果通过对System.Object的引用调用运算符,则不会调用该重定义的运算符.

对于字符串,没有什么区别,因为已经重写了==和Equals来比较字符串的内容.

另请参阅另一个问题的答案("如何在没有无限递归的情况下检查'=='运算符重载中的空值?").



165> Rytmis..:

显式接口成员实现,其中实现接口成员,但隐藏除非将实例强制转换为接口类型.



166> Rob..:

这不是C#特定类型,但我刚刚找到了ISurrogateSelector和ISerializationSurrogate接口 -

http://msdn.microsoft.com/en-us/library/system.runtime.serialization.isurrogateselector.aspx

http://msdn.microsoft.com/en-us/library/system.runtime.serialization.isurrogateselector.aspx

将这些与BinaryFormatter结合使用可以通过实现代理类来序列化非可序列化对象.代理模式在计算机科学中是很好理解的,特别是在处理序列化问题时.我认为这个实现只是作为BinaryFormatter的构造函数的参数隐藏起来,这太糟糕了.

仍然 - 非常隐藏.:)



167> amazedsaint..:

C#4.0中的动态关键字

如果希望仅在运行时解析方法调用,则可以使用dynamic关键字.

dynamic invoker=new DynamicInvoker();
dynamic result1=invoker.MyMethod1();
dynamic result2=invoker.MyMethod2();

在这里,我正在实现一个动态调用程序.

public class DynamicInvoker : IDynamicObject
    {
        public MetaObject GetMetaObject
              (System.Linq.Expressions.Expression parameter)
        {
            return new DynamicReaderDispatch (parameter);
        }
    }

    public class DynamicDispatcher : MetaObject
    {
        public DynamicDispatcher (Expression parameter) 
                   : base(parameter, Restrictions.Empty){ }

        public override MetaObject Call(CallAction action, MetaObject[] args)
        {
            //You'll get MyMethod1 and MyMethod2 here (and what ever you call)
            Console.WriteLine("Logic to invoke Method '{0}'", action.Name);
            return this; //Return a meta object
        }
    }



168> JohnOpincar..:

您可以在非泛型类中使用泛型方法.



169> Andrew Peter..:

使用lambda时模拟功能性"通配符"参数(如Haskell中的"_")的酷技巧:

(_, b, __) => b.DoStuff();  // only interested in b here


这不是一个技巧,只是一个命名选择.我觉得它看起来很愚蠢,因为你不得不使用越来越多的下划线.

170> DSO..:

这是我最近发现的一个有用的:

Microsoft.VisualBasic.Logging.FileLogTraceListener

MSDN链接

这是一个TraceListener实现,它具有许多功能,例如自动日志文件翻转,我以前会使用自定义日志记录框架.好处是它是.NET的核心部分,并与Trace框架集成,因此易于立即使用和使用.

这是"隐藏"的,因为它在Microsoft.VisualBasic程序集中......但您也可以在C#中使用它.



171> Elroy..:

在通用代码中使用default关键字来返回类型的默认值.

public class GenericList
{
    private class Node
    {
        //...

        public Node Next;
        public T Data;
    }

    private Node head;

    //...

    public T GetNext()
    {
        T temp = default(T);

        Node current = head;
        if (current != null)
        {
            temp = current.Data;
            current = current.Next;
        }
        return temp;
    }
}

另一个例子



172> Ash..:

当您想要Invoke/BeginInvoke内联代码时,内置(2.0)MethodInvoker委托很有用.这避免了需要创建实际的委托和单独的方法.

    void FileMessageEvent(object sender, MessageEventArgs e)
    {

        if (this.InvokeRequired == true)
        {
            this.BeginInvoke((MethodInvoker)delegate { 
                     lblMessage.Text=e.Message; 
                     Application.DoEvents(); 
                 }
            ); 

        }
    }

解决了错误:"无法将匿名方法转换为'System.Delegate',因为它不是委托类型".



173> JoshL..:

数组初始化而不指定数组元素类型:

var pets = new[] { "Cat", "Dog", "Bird" };


还有:`string [] pets = {"Cat","Dog","Bird"};`

174> Lloyd Powell..:

查看组件时要显示的属性设计视图中的属性:

private double _Zoom = 1;

[Category("View")]
[Description("The Current Zoom Level")]
public double Zoom
{
get { return _Zoom;}
set { _Zoom = value;}
}

使组件库的其他用户更容易.



175> ShuggyCoUk..:

高级调试

显示

已提到的属性DebuggerDisplay和DebuggerBrowsable控制元素的可见性和显示的文本值.简单地重写ToString()将导致调试器使用该方法的输出.

如果您想要更复杂的输出,可以使用/创建Debugger Visualizer,这里有几个示例.

罢工的儿子

Microsoft提供称为SOS的调试器扩展.这是一个非常强大(虽然经常令人困惑)的扩展,这是诊断"泄漏"的一种很好的方法,更准确地说是对不再需要的对象的不必要的引用.

用于框架源的Symbol Server

遵循这些说明将允许您逐步完成框架的某些部分的来源.

2010年的变化

Visual Studio 2010中存在一些增强功能和新功能:

调试并行任务

并行堆栈允许同时查看多个线程调用堆栈.

历史调试允许您及时查看事件和非局部变量(只要您提前启用集合).可能是对调试方式的重大改变.



176> SLaks..:

您可以使用扩展方法创建委托,就好像它们是常规方法一样,从而调整this参数.例如,

static class FunnyExtension {
    public static string Double(this string str) { return str + str; }
    public static int Double(this int num) { return num + num; }
}


Func aaMaker = "a".Double;
Func doubler = FunnyExtension.Double;

Console.WriteLine(aaMaker());       //Prints "aa"
Console.WriteLine(doubler("b"));    //Prints "bb"

请注意,这不适用于扩展值类型的扩展方法; 看到这个问题.



177> 小智..:
HttpContext.Current.Server.Execute 

非常适合将HTML呈现为AJAX回调的字符串.您可以将其与组件一起使用,而不是拼凑HTML字符串片段.我能够将页面臃肿减少几百KB,几乎没有任何混乱.我用它是这样的:

Page pageHolder = new Page();
UserControl viewControl = (UserControl)pageHolder.LoadControl(@"MyComponent.ascx");
pageHolder.Controls.Add(viewControl);
StringWriter output = new StringWriter();
HttpContext.Current.Server.Execute(pageHolder, output, false);
return output.ToString();



178> Martin Konic..:
[field: NonSerialized]
public event EventHandler Event;

这样,事件侦听器就不会被序列化.

只是[NonSerialized]不起作用,因为NonSerializedAttribute只能应用于字段.



179> ata..:

我不认为有人提到追加?在值类型名称之后将使其可为空.

你可以做:

DateTime? date = null;

DateTime是一个结构.



180> Ali Ersöz..:

Eric Lippert的四个开关怪异



181> 小智..:

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



182> Nakul Chaudh..:

我喜欢

#if DEBUG
           //Code run in debugging mode

#else
           //Code run in release mode

#endif


虽然这可以很方便,但应小心使用.我见过几种情况,部署的代码与本地代码的行为不同.
使用`Conditional`属性通常比使用`#if`更好.http://msdn.microsoft.com/en-us/library/aa664622%28VS.71%29.aspx

183> Pretzel..:

我正在通过"Pro ASP.NET MVC框架"(APress)这本书阅读并观察到作者正在使用对我来说很陌生的Dictionary对象.

他在不使用Add()方法的情况下添加了一个新的键/值对.然后他覆盖相同的键/值对,而不必检查该键是否已存在.例如:

Dictionary nameAgeDict = new Dictionary();
nameAgeDict["Joe"] = 34;      // no error. will just auto-add key/value
nameAgeDict["Joe"] = 41;      // no error. key/value just get overwritten
nameAgeDict.Add("Joe", 30);   // ERROR! key already exists

在许多情况下,我不需要检查我的词典是否已经有一个键,我只想添加相应的键/值对(如果需要,覆盖现有的键/值对.)在此发现之前,我总是要在添加之前检查密钥是否已经存在.



184> WedTM..:

不确定这个是否被提及(11页!!)

但是,OptionalField当您对将要序列化的类/对象进行版本控制时,类的属性是惊人的.

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



185> Iain Holder..:

@Brad Barker

我认为如果你必须使用可空类型,最好使用Nullable <.T>而不是问号符号.令人惊讶的是,魔法正在发生.不知道为什么有人会想要使用Nullable <.bool>.:-)

Krzysztof Cwalina(Framwork Design Guidlines的作者之一)在这里有一篇好文章:http: //blogs.msdn.com/kcwalina/archive/2008/07/16/Nullable.aspx

Mike Hadlow在Nullability Voodoo上发表了一篇不错的帖子



186> BinaryMisfit..:

没有特别的顺序:

Lists<>
Mutex

Framework 3.5中的新属性定义快捷方式.



187> David Basara..:

在阅读有关.NET框架开发的书中.一个很好的建议是不要使用bool打开或关闭东西,而是使用ENums.

使用ENums,您可以为自己提供一些可扩展性,而无需重写任何代码来为函数添加新功能.



188> chakrit..:

想到@dp AnonCast并决定尝试一下.以下是我提出的可能对某些人有用的内容:

// using the concepts of dp's AnonCast
static Func TypeCurry(Func f, T type)
{
    return () => (T)f();
}


以下是它的使用方法:

static void Main(string[] args)
{

    var getRandomObjectX = TypeCurry(GetRandomObject,
        new { Name = default(string), Badges = default(int) });

    do {

        var obj = getRandomObjectX();

        Console.WriteLine("Name : {0} Badges : {1}",
            obj.Name,
            obj.Badges);

    } while (Console.ReadKey().Key != ConsoleKey.Escape);

}

static Random r = new Random();
static object GetRandomObject()
{
    return new {
        Name = Guid.NewGuid().ToString().Substring(0, 4),
        Badges = r.Next(0, 100)
    };
}



189> Sixto Saez..:

新修饰语

在C#中使用"new"修饰符并没有完全隐藏,但它并不常见.当您需要"隐藏"基类成员而不是总是覆盖它们时,new修饰符会派上用场.这意味着当您将派生类转换为基类时,"隐藏"方法变为可见,并且在派生类中调用而不是相同的方法.

在代码中更容易看到:

public class BaseFoo
{
    virtual public void DoSomething()
    {
        Console.WriteLine("Foo");
    }
}

public class DerivedFoo : BaseFoo
{
    public new void DoSomething()
    {
        Console.WriteLine("Bar");
    }
}

public class DerivedBar : BaseFoo
{
    public override void DoSomething()
    {
        Console.WriteLine("FooBar");
    }
}

class Program
{
    static void Main(string[] args)
    {
        BaseFoo derivedBarAsBaseFoo = new DerivedBar();
        BaseFoo derivedFooAsBaseFoo = new DerivedFoo();

        DerivedFoo derivedFoo = new DerivedFoo();

        derivedFooAsBaseFoo.DoSomething(); //Prints "Foo" when you might expect "Bar"
        derivedBarAsBaseFoo.DoSomething(); //Prints "FooBar"

        derivedFoo.DoSomething(); //Prints "Bar"
    }
}

[艾德:我为双关语获得额外积分吗?对不起,无法帮助.]



190> ilitirit..:

文字可以用作该类型的变量.例如.

Console.WriteLine(5.ToString());
Console.WriteLine(5M.GetType());   // Returns "System.Decimal"
Console.WriteLine("This is a string!!!".Replace("!!", "!"));

只是一点点琐事......

人们没有提到过很多东西,但它们主要与不安全的构造有关.以下是"常规"代码可以使用的代码:

选中/未选中的关键字:

public static int UncheckedAddition(int a, int b)
{
    unchecked { return a + b; }
}

public static int CheckedAddition(int a, int b)
{
    checked { return a + b; } // or "return checked(a + b)";
}

public static void Main() 
{
    Console.WriteLine("Unchecked: " + UncheckedAddition(Int32.MaxValue, + 1));  // "Wraps around"
    Console.WriteLine("Checked: " + CheckedAddition(Int32.MaxValue, + 1));  // Throws an Overflow exception
    Console.ReadLine();
}



191> Patrick Szal..:

而不是使用int.TryParse()或Convert.ToInt32(),我喜欢有一个静态整数解析函数,当它无法解析时返回null.然后我可以用?? 和三元运算符一起更清楚地确保我的声明和初始化都以易于理解的方式在一行上完成.

public static class Parser {
    public static int? ParseInt(string s) {
        int result;
        bool parsed = int.TryParse(s, out result);
        if (parsed) return result;
        else return null;
    }
    // ...
}

这也有助于避免重复赋值的左侧,但更好的是避免在赋值的右侧重复长调用,例如以下示例中的数据库调用.而不是丑陋的if-then树(我经常遇到):

int x = 0;
YourDatabaseResultSet data = new YourDatabaseResultSet();
if (cond1)
    if (int.TryParse(x_input, x)){
        data = YourDatabaseAccessMethod("my_proc_name", 2, x);
    }
    else{
        x = -1;
        // do something to report "Can't Parse"    
    }
}
else {
    x = y;
    data = YourDatabaseAccessMethod("my_proc_name", 
       new SqlParameter("@param1", 2),
       new SqlParameter("@param2", x));
}

你可以做:

int x = cond1 ? (Parser.ParseInt(x_input) ?? -1) : y;
if (x >= 0)  data = YourDatabaseAccessMethod("my_proc_name", 
    new SqlParameter("@param1", 2),
    new SqlParameter("@param2", x));

更清洁,更容易理解



192> Cohen..:

Math.Max和Min检查边界:我在很多代码中都看到了这个:

if (x < lowerBoundary) 
{
   x = lowerBoundary;
}

我觉得这个更小,更干净,更可读:

x = Math.Max(x, lowerBoundary);

或者您也可以使用三元运算符:

x = ( x < lowerBoundary) ? lowerBoundary : x;



193> Dmitri Neste..:

Mixins是一个很好的功能.基本上,mixins让你有一个接口而不是类的具体代码.然后,只需在一堆类中实现该接口,您就可以自动获得mixin功能.例如,要将深度复制混合到多个类中,请定义一个接口

internal interface IPrototype { }

添加此接口的功能

internal static class Prototype
{
  public static T DeepCopy(this IPrototype target)
  {
    T copy;
    using (var stream = new MemoryStream())
    {
      var formatter = new BinaryFormatter();
      formatter.Serialize(stream, (T)target);
      stream.Seek(0, SeekOrigin.Begin);
      copy = (T) formatter.Deserialize(stream);
      stream.Close();
    }
    return copy;
  }
}

然后实现任何类型的接口以获得mixin.



194> Eyvind..:

关于foreach:它不使用'duck typing',因为鸭子输入IMO指的是运行时检查.它在编译时使用结构类型检查(与标称相反)来检查类型中所需的方法.



195> Bryan Watts..:

(我刚刚使用了这个)将字段设置为null并返回它而没有中间变量:

try
{
    return _field;
}
finally
{
    _field = null;
}


聪明,但难以阅读.当他们在代码中看到"尝试"时,大多数开发人员都会正确地尝试/捕获.另外,我想不出很多有用的情况.可能有一个属性来包装该成员,并且在世界上你有一个类似于DoSomestuffToAMemberReturnItToMeThenNullIt()的方法吗?呵呵.似乎违反直觉.我和Guillaume在这一个.

196> Steven Behnk..:

这不是C#特有的功能,但它是一个我发现非常有用的插件.它被称为资源重构工具.它允许您右键单击文字字符串并将其提取到资源文件中.它将搜索代码并查找匹配的任何其他文字字符串,并将其替换为Resx文件中的相同资源.

http://www.codeplex.com/ResourceRefactoring



197> 小智..:

我称之为AutoDebug是因为您可以根据bool值直接调入调试的位置,也可以将其存储为项目用户设置.

例:

//Place at top of your code
public UseAutoDebug = true;


//Place anywhere in your code including catch areas in try/catch blocks
Debug.Assert(!this.UseAutoDebug);

只需将上面的内容放在try/catch块或代码的其他区域中,并将UseAutoDebug设置为true或false,并在您希望进行测试时随时进入调试.

您可以保留此代码并在测试时打开和关闭此功能,您也可以将其保存为项目设置,并在部署后手动更改它,以便在/如果需要时从用户那里获取其他错误信息.

您可以在此Visual Studio C#项目模板中看到使用此技术的功能和实际示例,其中大量使用它:

http://code.msdn.microsoft.com/SEHE



198> Jonathan Par..:

方法组并不为人所知.

鉴于:

Func,int,int> myFunc1 = (i, j) => i(j);
Func myFunc2 = i => i + 2;

你可以这样做:

var x = myFunc1(myFunc2, 1);

而不是这个:

var x = myFunc1(z => myFunc2(z), 1);



199> Jeff Yates..:

我对这个问题这么迟,但我想补充一些我认为没有涵盖的问题.这些不是C#特定的,但我认为对于任何C#开发人员来说都值得一提.

AmbientValueAttribute

这类似于DefaultValueAttribute,但不是提供属性默认的值,而是提供属性用于决定是否从其他位置请求其值的值.例如,对于WinForms中的许多控件,它们ForeColorBackColor属性都有一个AmbientValue,Color.Empty以便他们知道从父控件中获取颜色.

IsolatedStorageSettings

这是一个Silverlight.该框架轻松地包含这个密封类,用于在每个应用程序和每个站点级别提供设置持久性.

标记与扩展方法的交互

使用扩展方法,标记枚举使用可以更具可读性.

    public static bool Contains(
          this MyEnumType enumValue,
          MyEnumType flagValue)
    {
        return ((enumValue & flagValue) == flagValue);
    }

    public static bool ContainsAny(
          this MyEnumType enumValue,
          MyEnumType flagValue)
    {
        return ((enumValue & flagValue) > 0);
    }

这使得检查标志值很好并且易于读写.当然,如果我们可以使用泛型并强制使用T作为枚举会更好,但这是不允许的.也许dynamic会让这更容易.



200> Josef Pflege..:

我发现令人难以置信的是编译器通过糖代码使用外部变量会遇到什么样的麻烦:

string output = "helo world!";
Action action = () => Console.WriteLine(output);
output = "hello!";
action();

这实际上打印hello!.为什么?因为编译器为委托创建了一个嵌套类,所有外部变量都有公共字段,并且在每次调用委托之前插入设置代码:)以上是代码'reflectored':

Action action;
<>c__DisplayClass1 CS$<>8__locals2;
CS$<>8__locals2 = new <>c__DisplayClass1();
CS$<>8__locals2.output = "helo world!";
action = new Action(CS$<>8__locals2.
b__0); CS$<>8__locals2.output = "hello!"; action();

我觉得很酷.



201> Shalom Craim..:

我无法弄清楚Convert类中的某些函数有什么用(例如Convert.ToDouble(int),Convert.ToInt(double)),直到我将它们与Array.ConvertAll:

int[] someArrayYouHaveAsInt;
double[] copyOfArrayAsDouble = Array.ConvertAll(
                                someArrayYouHaveAsInt,
                                new Converter(Convert.ToDouble));

这避免了定义内联委托/闭包(稍微更具可读性)引起的资源分配问题:

int[] someArrayYouHaveAsInt;
double[] copyOfArrayAsDouble = Array.ConvertAll(
                                someArrayYouHaveAsInt,
                                new Converter(
                                  delegate(int i) { return (double)i; }
                                ));



202> M. Dudley..:

刚刚学习了不变性,协方差和逆变的意义后,我发现了将包含在.NET 4.0中的in和out泛型修饰符.它们似乎模糊不清,大多数程序员都不会知道它们.

Visual Studio Magazine 上有一篇文章讨论了这些关键字及其使用方法.



203> Tolgahan Alb..:

可以为枚举定义数据类型:

enum EnumName : [byte, char, int16, int32, int64, uint16, uint32, uint64]
{
    A = 1,
    B = 2
}


以上大部分功能也都有记录.

204> statenjason..:

Yield关键字在具有很大功率时经常被忽略.我之前在博客上讨论了这个问题并讨论了好处(不同的处理方式),并在收益率的引导下发生,以帮助提供更强的理解.

在C#中使用Yield



205> softveda..:

C#中的指针.

它们可用于执行就地字符串操作.这是一个不安全的功能,因此unsafe关键字用于标记不安全代码的区域.另请注意固定关键字如何用于指示指向的内存是固定的,并且不能由GC移动.这是指向内存地址的指针必不可少的,GC可以将内存移动到不同的地址,否则会导致指针无效.

    string str = "some string";
    Console.WriteLine(str);
    unsafe
    {
        fixed(char *s = str)
        {
            char *c = s;
            while(*c != '\0')
            {
                *c = Char.ToUpper(*c++);                    
            }
        }
    }
    Console.WriteLine(str);

我不会这样做,只是为了这个问题来展示这个功能.


不一定......使用不安全的代码可能会显着提高性能,请参阅"http://stackoverflow.com/questions/541331/effective-way-of-making-negative-of-image-without-external-dlls"

206> 小智..:

我特别喜欢可以为空的DateTime.因此,如果你有一些日期给出的情况和其他没有给出日期的情况,我认为这是最好的使用和恕我直言,更容易理解为使用DateTime.MinValue或其他任何事情......

DateTime? myDate = null;

if (myDate.HasValue)
{
    //doSomething
}
else
{
    //soSomethingElse
}



207> Mike Valenty..:

开放式泛型是另一个方便的功能,尤其是在使用控制反转时:

container.RegisterType(typeof(IRepository<>), typeof(NHibernateRepository<>));


究竟是做什么的?

208> t0mm13b..:

仔细阅读了所有9页,我觉得我必须指出一些未知的特征......

这适用于.NET 1.1,在gzip压缩文件上使用压缩/解压缩,其中一个必须:

下载ICSharpCode.ZipLib

或者,将Java库引用到您的项目中,并使用Java的内置库来利用GZip的压缩/解压缩方法.

它未被充分利用,我还不知道,(仍然使用ICSharpCode.ZipLib,即使使用.NET 2/3.5)它是在System.IO.Compression命名空间中被合并到标准BCL版本2中. .请参阅MSDN页面" GZipStream类 ".



209> Jamie Keelin..:

我发现在Visual Studio中使用条件中断函数非常有用.我喜欢它允许我将值设置为某种东西的方式,例如只能在极少数情况下才能满足,并且从那里我可以进一步检查代码.



210> Navid Farhad..:

这意味着T必须具有公共无参数构造函数:

 class MyClass where T : new()
 {

 }



211> AaronLS..:

从匿名方法访问局部变量允许您使用新的控制流逻辑包装任何代码,而不必将该代码分解为另一种方法.在方法内部声明的局部变量在方法中可用endOfLineChar,例如此处示例中的局部变量:

http://aaronls.wordpress.com/2010/02/02/retrying-on-exception-conditionally/



212> John Boker..:

@lainMH,

当从可以为空的数据库中检索值并将值重新放入时,可以为空的布尔值非常有用.有时您想知道该字段尚未设置.



213> Drakiula..:

想到反射Emit和表达树......

不要错过Jeffrey Richter通过C#和Jon Skeet的CLR 替代文字

在这里查看一些资源:

http://www.codeproject.com/KB/trace/releasemodebreakpoint.aspx

http://www.codeproject.com/KB/dotnet/Creating_Dynamic_Types.aspx

http://www.codeproject.com/KB/cs/lambdaexpressions.aspx



214> Thomas Danec..:

System.Runtime.Remoting.Proxies.RealProxy

它可以在C#中实现面向方面编程,你也可以用它做很多其他的花哨的东西.



215> sbeskur..:

在使用linqxml时,我发现这项技术很有趣:

public bool GetFooSetting(XElement ndef){
   return (bool?)ndef.Element("MyBoolSettingValue") ?? true;
}

而不是:

public bool GetFooSetting(XElement ndef){
   return ndef.Element("MyBoolSettingValue") != null ? bool.Parse(ndef.Element("MyBoolSettingValue") ) : true;
}



216> 小智..:

通用事件处理程序:

public event EventHandler MyEvent;

这样您就不必一直声明自己的代理,



217> Gavin Miller..:

我没有发现 - 近一年 - 强类型DataRows包含一个Is [ColumnName] Null()方法.

例如:

Units.UnitsDataTable dataTable = new Units.UnitsDataTable();

foreach (Units.UnitsRow row in dataTable.Rows)
{
    if (row.IsPrimaryKeyNull())
        //....

    if (row.IsForeignKeyNull())
        //....
}


要挑剔,它不是C#功能,它是.NET功能;)

218> kentaromiura..:

构造链是否已被引用?

namespace constructorChain {
    using System;

    public class Class1 {
        public string x;
        public string y;

        public Class1() {
            x = "class1";
            y = "";
        }

        public Class1(string y)
            : this() {
            this.y = y;
        }
    }

    public class Class2 : Class1 {
        public Class2(int y)
            : base(y.ToString()) {

        }
    }
}

...

        constructorChain.Class1 c1 = new constructorChain.Class1();
        constructorChain.Class1 c12 = new constructorChain.Class1("Hello, Constructor!");
        constructorChain.Class2 c2 = new constructorChain.Class2(10);
        Console.WriteLine("{0}:{1}", c1.x, c1.y);
        Console.WriteLine("{0}:{1}", c12.x, c12.y);
        Console.WriteLine("{0}:{1}", c2.x, c2.y);

        Console.ReadLine();


每次有包含相同初始化代码的构造函数时,构造函数链都会避免代码重复.

219> Akash Kava..:

C#中指针的固定 /功能 - 这个主题太大了,但我只是简单介绍一下.

在C我们有装载结构的设施,如...

struct cType{
   char type[4];
   int  size;
   char name[50];
   char email[100];
}

cType myType;
fread(file, &mType, sizeof(mType));

我们可以在"unsafe"方法中使用fixed关键字来读取字节数组对齐的结构.

[Layout(LayoutKind.Sequential, Pack=1)]
public unsafe class CType{
    public fixed byte type[4];
    public int size;
    public fixed byte name[50];
    public fixed byte email[100];
}

方法1(从常规流读取到字节缓冲区并将字节数组映射到struct的各个字节)

CType mType = new CType();
byte[] buffer = new byte[Marshal.SizeOf(CType)];
stream.Read(buffer,0,buffer.Length);
// you can map your buffer back to your struct...
fixed(CType* sp = &mType)
{
    byte* bsp = (byte*) sp;
    fixed(byte* bp = &buffer)
    {
         for(int i=0;i

方法2,你可以映射Win32 User32.dll的ReadFile直接读取字节...

CType mType = new CType();
fixed(CType* p = &mType)
{
    User32.ReadFile(fileHandle, (byte*) p, Marshal.SizeOf(mType),0);
}



220> David.Chu.ca..:

我喜欢使用using指令重命名一些类,以便于阅读:

// defines a descriptive name for a complexed data type
using MyDomainClassList = System.Collections.Generic.List<
  MyProjectNameSpace.MyDomainClass>;

....


MyDomainClassList myList = new MyDomainClassList();
/* instead of 
List myList = new List();
*/

这对于代码维护也非常方便.如果您需要更改类名,则只需要更改一个位置.另一个例子:

using FloatValue  = float; // you only need to change it once to decimal, double...

....
FloatValue val1;
...



221> Paul van Bre..:

零参数Lambdas

()=>Console.ReadLine()



222> ccook..:

我没有看到这个:

for (;;);

同样的

while (true) ;



223> mezoid..:

我刚刚学到的一个问题是你仍然可以在一个可以为空的值上调用方法 ....

当你有一个可以为空的值时,结果是什么:

decimal? MyValue = null;

您可能认为必须写的地方:

MyValue == null ? null : MyValue .ToString()

你可以写:

MyValue.ToString()

我已经知道我可以调用MyValue.HasValue和MyValue.Value ......但它没有完全点击我可以调用ToString().



224> manji..:

这不会编译:

namespace ns
{
    class Class1
    {
        Nullable a;
    }
}

找不到类型或命名空间名称'Nullable'(您是否缺少using指令或程序集引用?) < - missing' using System;'

namespace ns
{
    class Class1
    {
        int? a;
    }
}

会编译!(.NET 2.0).



225> Todd Richard..:

如果有人提到这个,我道歉,但我经常使用它.

Visual Studio的加载项由Alex Papadimoulis开发.它用于将常规文本粘贴为字符串,字符串构建器,注释或区域.

http://weblogs.asp.net/alex_papadimoulis/archive/2004/05/25/Smart-Paster-1.1-Add-In---StringBuilder-and-Better-C_2300_-Handling.aspx

在这个插件中(我也不知道是否已经提到过)我注意到字符串是用字符串文字前缀粘贴的:

@

我知道这些,但我不知道在文字中使用双引号来逃避引用.

例如

string s = "A line of text" + Environment.NewLine + "Another with a \"quote\"!!";

可以表达为

string s = @"A line of text 
Another with a ""quote""!!";



226> Brian..:

我喜欢EditorBrowsableAttribute.它允许您控制是否在Intellisense中显示方法/属性.您可以将值设置为"始终","高级"或"从不".

来自MSDN ......

备注

EditorBrowsableAttribute是设计器的提示,指示是否要显示属性或方法.您可以在可视化设计器或文本编辑器中使用此类型来确定用户可见的内容.例如,Visual Studio中的IntelliSense引擎使用此属性来确定是否显示属性或方法.

在Visual C#中,您可以在"工具"下的"智能感知"和"属性"窗口中使用"隐藏高级成员"设置控制何时显示高级属性 选项| 文字编辑器| C#.相应的EditorBrowsableState为Advanced.



227> Zac Bowling..:

__arglist也是

[DllImport("msvcrt40.dll")]
public static extern int printf(string format, __arglist);

static void Main(string[] args)
{
   printf("Hello %s!\n", __arglist("Bart"));
}



228> Dave Jelliso..:

Action和Func将帮助器与lambda方法一起委托.我将这些用于需要委托以提高可读性的简单模式.例如,一个简单的缓存模式是检查缓存中是否存在请求的对象.如果确实存在:返回缓存的对象.如果它不存在,则生成新实例,缓存新实例并返回新实例.相反,我可以从缓存中存储/检索的每个对象写入此代码1000次,我可以编写一个简单的模式方法,如此...

private static T CachePattern(string key, Func create) where T : class
{
    if (cache[key] == null)
    {
        cache.Add(key, create());
    }

    return cache[key] as T;
}

...然后我可以通过在我的自定义缓存管理器中使用以下内容来大大简化我的缓存获取/设置代码

public static IUser CurrentUser
{
    get
    {
        return CachePattern("CurrentUserKey", () => repository.NewUpUser());
    }
}

现在,简单的"日常"代码模式可以编写一次,并且可以更轻松地重复使用恕我直言.我不必编写委托类型并弄清楚我想如何实现回调等.如果我能在10秒内写出来,那我就不那么贴切了.求助于剪切/粘贴简单的代码模式,无论它们是惰性初始化还是上面显示的其他一些例子......



229> Anthony Mast..:

允许带有大括号的空块.

你可以写这样的代码

{
    service.DoTonsOfWork(args);
}

当你想要在没有usingtry... finally已经写过的情况下尝试某些东西时,它会很有用.

//using(var scope = new TransactionScope)
{
    service.DoTonsOfWork(args);
}


它也可以作为其他类型嵌套的视觉指示器.例如,我经常使用大括号将语句嵌套在`Debug.Indent()`和`Debug.Unindent`之间.
它们对于限制变量的范围很有用

230> Snake..:

Nullable.GetValueOrDefault?

推荐阅读
李桂平2402851397
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有