C#的隐藏功能?[关闭]


1475

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

where T : struct

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

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

但是,即使C#爱好者,成瘾者,专家也几乎不知道C#最隐藏的功能或技巧是什么?

到目前为止,这里是一些揭示的功能:


关键词

属性

句法

语言功能

Visual Studio功能

构架

方法和性质

提示与技巧

其他

Answers:


752

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

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

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

584

lambda和类型推断被低估了。Lambda可以具有多个语句,并且它们可以自动兼用作兼容的委托对象(只需确保签名匹配),如下所示:

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

请注意,我没有new CancellationEventHandler或也不必指定sender和的类型e,它们可以从事件中推断出来。这就是为什么这样写起来就不那么麻烦,delegate (blah blah)它也要求您指定参数的类型。

Lambda不需要返回任何内容,并且在这种情况下类型推断非常强大。

顺便说一句,您始终可以返回从函数编程意义上构成Lambda的Lambda。例如,以下是一个lambda,它使lambda可以处理Button.Click事件:

Func<int, int, EventHandler> makeHandler =
    (dx, dy) => (sender, e) => {
        var btn = (Button) sender;
        btn.Top += dy;
        btn.Left += dx;
    };

btnUp.Click += makeHandler(0, -1);
btnDown.Click += makeHandler(0, 1);
btnLeft.Click += makeHandler(-1, 0);
btnRight.Click += makeHandler(1, 0);

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

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

除了C中的指针,我认为这是您还应该学习的另一项基本知识:-)



454

别名泛型:

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

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

当您将在许多地方使用相同的通用大型长复杂事物时,请使用它。


438

CLR通过C#

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

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


254
当“将字符串转换为大写”时,将创建第二个临时字符串对象。我认为这种比较不是优选的,最好的方法是:String.Equals(stringA,stringB,StringComparison.CurrentCultureIgnoreCase)根本不会创建该丢弃的字符串。
安东尼

32
在比较大写字符串时,您可以执行哪种优化,而在小写字符串上却无法完成?我不明白为什么一个会比另一个更好。
帕拉帕

36
转换为大写而不是小写也可以防止某些区域性的错误行为。例如,在土耳其语中,两个小写字母i映射到相同的大写字母I。有关更多详细信息,请使用Google“土耳其语i”。
尼尔

34
我尝试了基准测试ToUpperInvariant与ToLowerInvariant。在.NET 2.0或3.5下,我找不到它们的性能差异。当然,没有什么值得“高度推荐”的。
Rasmus Faber

19
首选ToUpperInvariant,因为它会使所有字符都往返。请参阅msdn.microsoft.com/en-us/library/bb386042.aspx。为了进行比较,请写"a".Equals("A", StringComparison.OrdinalIgnoreCase)
-SLaks

408

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

private IList<Foo> _foo;

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

23
你不觉得很难读吗?
里里(Riri)

72
对于新手来说,它有点难以阅读...呃,没有经验。但是它紧凑,并包含程序员应该了解和理解的几种模式和语言功能。因此,尽管一开始很难,但它提供了成为学习理由的好处。

38
延迟实例化在某种程度上是不当行为,因为它是避免考虑类不变式的不明智选择。它还具有并发问题。
约翰·莱德格伦

17
我一直被告知这是一种不好的做法,调用属性不应这样做。如果您在那里设置了一个值并将其值设置为null,那么对于使用您的API的用户来说,这将非常奇怪。
伊恩

8
@Joel,只是将ListOfFoo设置为null既不是类协定的一部分,也不是一种好习惯。这就是为什么没有二传手。这也是为什么ListOfFoo可以保证返回一个集合且永远不会为null的原因。这是一个非常奇怪的抱怨,如果您做两个坏事(创建一个setter并将一个collection设置为null),这将导致您的期望是错误的。我也不建议在getter中执行Environment.Exit()。但这也与这个答案无关。

315

避免检查空事件处理程序

在声明时向事件添加一个空的委托,从而消除了在调用它之前必须始终检查该事件是否为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的有关此主题的博客文章(以及可能的弊端)。


87
我相信如果您依赖此技术,然后必须序列化该类,则会出现问题。您将消除该事件,然后在反序列化时将获得NullRefference...。因此,您可以坚持做事的“老方法”。更安全
sirrocco

16
您仍然可以将事件处理程序设置为null,因此仍然可以获取null引用,并且仍然具有竞争条件。
罗伯特·保尔森

64
快速配置文件测试显示,没有null测试的虚拟预订事件处理程序所花费的时间是带有null测试的未预订事件处理程序的大约2倍。没有null测试的多播事件处理程序所花费的时间是具有null测试的单播事件处理程序的3.5倍。
P爸爸

54
这样就避免了只需要一个自订用户就可以进行空检查的情况。即使是空事件,它也会带来您不希望的开销。如果没有订阅者,则您根本不希望触发该事件,而不总是总是首先触发一个空的虚拟事件。我会考虑这个错误的代码。
基思

56
由于上述评论的原因,这是一个可怕的建议。如果必须使代码看起来“干净”,请使用扩展方法检查是否为null,然后调用该事件。具有修改权限的人一定应该在此答案中添加缺点。
格雷格,2009年

305

其他一切,再加上

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

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

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

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

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

3)匿名类型和初始化程序:

//Duck-typed: works with any .Add method.
var colours = new Dictionary<string, string> {
    { "red", "#ff0000" },
    { "green", "#00ff00" },
    { "blue", "#0000ff" }
};

int[] arrayOfInt = { 1, 2, 3, 4, 5 };

另一个:

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

public int MyId { get; private set; }

感谢@pzycoman提醒我:

5)命名空间别名(并非您可能需要此特殊区别):

using web = System.Web.UI.WebControls;
using win = System.Windows.Forms;

web::Control aWebControl = new web::Control();
win::Control aFormControl = new win::Control();

14
在#3中,您可以执行Enumerable.Range(1,5)
Echostorm

18
我认为您已经能够使用int [] nums = {1,2,3}初始化数组;从1.0开始:)甚至不需要“ new”关键字
Lucas

13
没有参数的lambda()=> DoSomething();
Pablo Retyk,2009年

5
我都用过{ 内部设置 }和{get; 保护集;},因此此模式是一致的。
基思

7
@Kirk Broadhurst-您是对的- new web.Control()在此示例中也可以使用。该::语法迫使它来治疗前缀命名空间的别名,所以你可以有一个名为类webweb::Control语法,仍能正常工作,而web.Control语法不知道是否检查类或命名空间。因此,我倾向于::在进行名称空间别名时始终使用。
基思2010年

286

我很长一段时间都不知道“ as”关键字了。

MyClass myObject = (MyClass) obj;

MyClass myObject = obj as MyClass;

如果obj不是MyClass,则第二个将返回null,而不是引发类强制转换异常。


42
不过不要过度。许多人似乎使用,因为他们更喜欢语法,即使他们想要(ToType)x的语义。
Scott Langham

4
我不认为它可以提供更好的性能。你有资料吗?(当转换失败但显然它......但是当你使用(MyClass的)投,失败是例外..而且极为罕见(如果发生的话),所以没有区别。
斯科特朗廷

7
仅当通常情况是强制转换失败时,此性能才更高。否则,直接投射(类型)对象会更快。但是,直接强制转换抛出异常要比返回null花费更长的时间。
Spence

15
就在与“ as”关键字相同的地方...“ is”关键字同样有用。
dkpatt,2009年

28
您可以滥用它,并在以后可能早有InvalidCastException的情况下使NullReferenceException失效。
AndreiRînea'09

262

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

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

6
应该注意,“自动属性”是仅C#3.0的功能吗?
Jared Updike

21
自动属性随3.0编译器一起引入。但是由于可以将编译器设置为输出2.0代码,因此它们可以正常工作。只是不要尝试在较旧的编译器中使用自动属性来编译2.0代码!
约书亚·香农

74
许多人没有意识到的是get和set可以具有不同的可访问性,例如:public string Name {get; 私人套装;}
Nader Shirazie 09年

7
自动属性的唯一问题是似乎无法提供默认的初始化值。
SteinÅsmul09年

7
@ANeves:不,不是。从该页面:DefaultValueAttribute不会使成员自动使用该属性的值进行初始化。您必须在代码中设置初始值。 [DefaultValue]用于设计器,因此它知道是否以粗体显示属性(表示非默认)。
罗杰·利普斯科姆

255

通用类型中的“默认”关键字:

T t = default(T);

如果T是引用类型,则结果为“ null”;如果它是int,则结果为0;如果它是布尔值,则结果为false,等等。


4
加号:类型?作为Nullable <type>的快捷方式。default(int)== 0,但default(int?)== null。
sunside


221

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

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

如果你有

string s = @"cat
             dog
             fish"

它实际上将打印为(请注意,它甚至包括用于缩进的空格):

cat
             dog
             fish

字符串不包括您用于缩进的所有空格吗?
安迪

18
是的,它称为逐字字符串。
Joan Venge

4
如果输出中也显示将要打印的空格,将会更加清楚。现在,好像换行符已被打印,但空格被忽略了。
aleemb

对于转义正则表达式和长SQL查询非常有用。
ashes999 2010年

它还映射{{{}}使其}对有用string.Format()
Ferruccio 2012年

220

我认为C#(.NET 3.5)最不被人赏识和鲜为人知的功能之一就是表达式树尤其是当与泛型和Lambda结合使用时。这是一种创建API的方法,较新的库(如NInject和Moq)正在使用。

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

给定本课:

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

以前,很常见的是,开发人员使用字符串和类型(或其他主要基于字符串的形式)执行此操作:

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

好吧,这是因为缺乏强类型性而令人讨厌。如果我重命名“ SomeMethod”怎么办?现在,在3.5版中,我可以采用强类型的方式进行此操作:

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

其中RegisterMethod类的用法Expression<Action<T>>如下:

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

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

这是我现在爱上Lambda和Expression Trees的重要原因之一。


3
我有一个反射实用程序类,它与FieldInfo,PropertyInfo等相同...
Olmo

是的,这很棒。我能够使用这种方法EditValue(someEmployee, e => e.FirstName);在业务逻辑中编写代码,并让它自动为ViewModel和View生成所有管道逻辑以编辑该属性(因此,带有文本“ First Name”的标签和带有TextBox的TextBox)当用户编辑名称并使用getter更新View时调用FirstName属性的setter的绑定)。这似乎是C#中大多数新内部DSL的基础。
Scott Whitlock,2010年

4
我认为这些并没有那么少为人所知。
贾斯汀·摩根

为什么需要注册方法?我以前从未使用过-何时何地使用它?
MoonKnight 2012年

209

我想到了“ 屈服 ”。一些属性,例如[DefaultValue()]也是我的最爱。

关键字“ var ”稍微有点知名,但是您似乎也可以在.NET 2.0应用程序中使用它(只要您使用.NET 3.5编译器并将其设置为输出2.0代码即可)好。

编辑:kokos,感谢您指出?运算符,确实非常有用。由于要对其进行搜索有点困难(因为??只是被忽略了),因此以下是该操作员的MSDN文档页面:?? 运算符(C#参考)


14
默认值的文档说,它并不是真正在设置属性的值。它只是可视化工具和代码生成器的帮助者。
鲍里斯·卡伦斯

2
至于DefaultValue:同时,一些库使用它。ASP.net MVC在控制器操作的参数上使用DefaultValue(这对于非空类型非常有用)。当然,严格来说,这是一个代码生成器,因为该值不是由编译器设置的,而是由MVC的代码设置的。
Michael Stum

6
??的名称 运算符为“空合并”运算符
阿姆斯特朗

产量是我的最爱,但是合并运算符在那里。我没有看到有关CAS或程序集签名,强名称,GAC的任何信息。我​​想只有CAS是C#了,但是很多开发人员对安全性一无所知。
BrainSlugs83 '02

198

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

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

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

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

关于Nullable类型的另一件事:

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

它是返回String.Empty。检查链接以获取更多详细信息


1
DateTime不能设置为null。
杰森·杰克逊

2
那么,“ int”仅仅是System.Int32的C#语法糖吗?实际上,围绕Nullable类型构建了编译器支持,例如,可以将它们设置为null(不能单独使用通用结构来完成),并将它们作为基础类型装箱。
P爸爸

4
@P Daddy-是的,int是System.Int32的语法糖。它们完全可以互换,就像int吗?=== Int32?=== Nullable <Int32> === Nullable <int>
2009年

6
@ck:是的,int是System.Int32的别名,如T?是可空的别名<T>,但它不是只是语法糖。这是语言的定义部分。别名不仅使代码更易于阅读,而且使模型更适合我们。将Nullable <Double>表示为double吗?强调了这样一个观点,即由此包含的值是(或可能是)双精度值,而不仅仅是在Double类型上实例化的某些通用结构。(续)
P Daddy

3
...在任何情况下,论点都不是关于别名的(我想这是一个很差的类推),但是可以为空的类型(使用您喜欢的语法)确实是一种语言功能,而不仅仅是泛型的产物。您不能as单独使用泛型来重现所有可为空的功能(与null的比较/分配,运算符转发,基础类型或null的装箱,与null合并和运算符的兼容性)。单独的Nullable <T>是基本的,并且远非恒星,但作为语言一部分的可空类型的概念却是kick脚。
P爸爸2009年

193

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

__makeref

__reftype

__refvalue

__arglist

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

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

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

最有用的“隐藏”功能是yield return关键字。它并不是真正的隐藏,但是很多人对此并不了解。LINQ基于此构建。它通过在后台生成状态机来允许延迟执行的查询。雷蒙德·陈(Raymond Chen)最近发布了有关内部细节的详细信息


2
彼得·布罗姆伯格(Peter Bromberg)对未记​​录关键字的更多详细信息。如果仍然有使用它们的理由,我仍然不了解。
HuBeZa'1

@HuBeZa随着泛型的出现,使用__refType,__makeref和__refvalue的理由不多(没有?)。这些被主要用于避免在.NET 2.泛型之前拳击
犹太加布里埃尔Himango

马特(Matt)在.NET 2中引入泛型时,几乎没有理由使用这些关键字,因为它们的目的是在处理值类型时避免装箱。参见HuBeZa的链接,还参见codeproject.com/Articles/38695/UnCommon-C-keywords-A-Look#ud
Judah Gabriel Himango 2011年

185

纯净,安全的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添加;


7
@George,当您使用c联合声明通过套接字与旧版应用程序通信时,会产生奇迹。
斯科特

2
int和float在偏移量0处也很有意义。如果要将浮点数作为位掩码来操纵,这就是您所需要的,有时您希望这样做。特别是如果您想学习有关浮点数的新知识。
约翰·莱德格伦

2
令人讨厌的事情是,如果您要使用它是一个结构,编译器将强制您在init函数中设置所有变量。因此,如果您有:public A(int int32){Int32 = int32; 它将抛出“必须将字段'One'完全分配,然后控制权才能返回给调用者”,因此您必须将One = 2 = 3 = 4 = 0;设置为0。也一样
manixrock

2
它有其用途,主要用于二进制数据。我使用一个int32 @ 0的“ Pixel”结构,以及四个字节@ 0、1、2和3的四个字节。非常适合快速,轻松地处理图像数据。
snarf

57
警告:此方法未考虑字节顺序。 这意味着您的C#代码不会在所有机器上以相同的方式运行。在小端CPU(首先存储最低有效字节)上,将使用所示的行为。但是在大端CPU上,字节输出将与您期望的相反。当心您如何在生产代码中使用此代码-您的代码可能无法移植到某些移动设备和其他硬件上,并且可能以非显而易见的方式中断(例如,两个文件表面上具有相同格式,但实际上字节顺序相反)。
雷·伯恩斯

176

将@用作关键字的变量名。

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

38
为什么要使用关键字作为变量名?在我看来,这会使代码的可读性和混淆性降低。
乔恩

41
嗯,之所以如此,是因为CLI要求它与其他可能使用C#关键字作为成员名称的语言进行互操作
Mark Cidade

69
如果您想使用asp.net MVC HTML帮助器并定义HTML类,您将很高兴知道可以使用@class,因此它不会被识别为class关键字
Boris Callens

31
非常适合扩展方法。公共静态无效DoSomething(this Bar @this,字符串foo){...}
Jonathan C Dickinson

45
@zihotki:错。var a = 5; Console.WriteLine(@a); 版画5
SLaks

168

如果要退出程序而不调用任何finally块或终结器,请使用FailFast

Environment.FailFast()

12
请注意,此方法还会创建内存转储并将消息写入Windows错误日志。
RickNZ

1
应该注意的是,使用此方法时不会调用终结器或应用程序域卸载事件...
AwkwardCoder 2010年

1
+1为提示,但这不是C#,它是.NET的BCL。
亚伯

。System.Diagnostics.Process.GetCurrentProcess()杀()速度更快
Tolgahan Albayrak的

153

从方法返回匿名类型并访问成员而无需进行反思。

// Useful? probably not.
private void foo()
{
    var user = AnonCast(GetUserTuple(), new { Name = default(string), Badges = default(int) });
    Console.WriteLine("Name: {0} Badges: {1}", user.Name, user.Badges);
}

object GetUserTuple()
{
    return new { Name = "dp", Badges = 5 };
}    

// Using the magic of Type Inference...
static T AnonCast<T>(object obj, T t)
{
   return (T) obj;
}

42
那真的什么都没给你。这实际上是危险的。如果修改了GetUserTuple以返回多种类型怎么办?强制转换将在运行时失败。C#/。Net的一大优点是编译时间检查。只创建一个新类型会更好。
杰森·杰克逊

9
@Jason我确实说过这可能没有用,但令人惊讶(我认为是隐藏的)。
丹尼斯·菲利斯

31
虽然很酷,但这似乎是一个较差的设计选择。您基本上已经在两个地方定义了匿名类型。此时,只需声明一个真实的结构并直接使用它即可。
Paul Alexander

6
@乔治:这样的约定将被称为...结构?
R. Martinho Fernandes

2
此技巧被称为“通过示例铸造”,如果返回匿名类型的方法位于另一个程序集中,则它将不起作用。
desco 2010年

146

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

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

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


27
另外,@常量在其中接受换行符。将多行脚本分配给字符串时非常理想。
Tor Haugen

11
换句话说,也不要忘记将引号引起来只是将其加倍。[code] var candy = @“我喜欢”“”“糖果棒。”; [/ code]
Dave

5
我倾向于使用Path.Combine构建路径。我绝对使用@作为正则表达式!
丹·麦克莱恩

6
@new也是变量而不是关键字:@ this,@ int,@ return,@ interface ...等等:)
IAbstract 2010年

这个问题并非遥不可及: 但是,即使C#爱好者,上瘾者,专家也几乎不知道C#最隐藏的功能或技巧是什么?
publicgk 2011年

141

Mixins。基本上,如果要向多个类添加功能,但不能对所有这些类都使用一个基类,请获取每个类以实现一个接口(无成员)。然后,为接口编写扩展方法,即

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

当然,牺牲了一些清晰度。但这有效!


4
是的,我认为这是扩展方法的真正力量。它们基本上允许接口方法的实现。
John Bubriski

如果您正在使用NHibernate(或Castle ActiveRecord),并且必须为集合使用接口,这也很方便。这样,您可以将行为赋予收集接口。
瑞安·伦迪

记录下来,基本上就是所有LINQ方法的实现方式。
WCWedin

这是一个谈论我上面提到的链接,在NHibernate或Castle ActiveRecord中使用带有集合接口的扩展方法:devlicio.us/blogs/billy_mccafferty/archive/2008/09/03/…–
Ryan Lundy

7
如果他们只允许扩展属性!我讨厌不得不写恳求是一个只读属性的扩展方法....
约翰·吉布

130

虽然不确定为什么有人会使用Nullable <bool>。:-)

是,否,FileNotFound


87
如果期望用户回答“是”,则没有问题,那么如果问题没有得到回答,则null为宜
Omar Kooheji

22
可空类型很容易与表列通常可为空的数据库进行交互。
tuinstoel

11
是的,不,Maybee?
丹·布莱尔

21
ThreeState CheckBox的存储值
Shimmy Weitzhandler,2009年

8
如在SQL中:是/否/未知。
erikkallen's

116

这个名称没有被“隐藏”,而是被错误地命名。

人们对算法“ map”,“ reduce”和“ filter”给予了极大的关注。大多数人没有意识到的是.NET 3.5添加了所有这三种算法,但是基于它们属于LINQ的事实,它给了它们非常类似于SQL的名称。

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

“ reduce” =>汇总
将值汇总为单个结果

“ filter” =>其中
根据条件过滤数据

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


1
Select也像monads中的“返回”功能一样。参见stackoverflow.com/questions/9033/hidden-features-of-c#405088
Mark Cidade

1
仅当使用SQLish语法时才需要使用“选择”。如果使用扩展方法语法-someCollection.Where(item => item.Price> 5.99M)-则不需要使用select语句。
布拉德·威尔逊

7
@Brad,那(其中)是一个过滤操作。尝试不执行选择操作进行地图操作
Eloff 2010年

2
LINQ是发生在C#在我看来天大的事情:stackoverflow.com/questions/2398818/...
Leniel Maccaferri

1
聚合的最小签名是“减少”功能,聚合的中间签名是更强大的“折叠”功能!
Brett Widmeier 2011年

115
Environment.NewLine

用于系统独立的换行符。


10
关于这一点的烦人的事情是它没有包含在紧凑框架中。
Stormenet

14
值得指出的是,这特定于应用程序的主机平台-因此,如果要创建用于其他系统的数据,则应适当使用\ n或\ r \ n。
网格

这是.NET BCL的一部分,而不是C#本身的功能。
亚伯

111

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

19
@Kyralessa:的确,是的,它们是花括号,但“花括号”是它们的替代名称。[]是方括号,<>是尖括号。请参阅en.wikipedia.org/wiki/Bracket
icktoofay 2010年

4
你是对的。但是当我发表评论时,并没有说“花括号”。
瑞安·伦迪

2
一个非常好的人指出。记住我的第一个String.Format看起来像:String.Format(“ {0}我在大括号中{1} {2} {3}”,“ {”,“}”,3,“瞎老鼠”);一旦发现转义是通过使用{{和}}来完成的,我真是很高兴:)
Gertjan 2010年

Muahahahaa ...在.Net中编程已有3年了,我不知道这一年。:D
Arnis Lapsa

“弯”括号的作用类似于转义序列?
Pratik 2010年

104
  1. ?? -合并运算符
  2. using(语句 / 指令)-很棒的关键字,它不仅可以用于调用Dispose,还可以用于其他用途
  3. 只读 -应该更多使用
  4. netmodules-太糟糕了,Visual Studio不支持

6
using也可以用于将长名称空间别名为更方便的字符串,即:using ZipEncode = MyCompany.UtilityCode.Compression.Zip.Encoding; 这里还有更多信息: msdn.microsoft.com/en-us/library/sf0df423.aspx
Dave R.

2
真的不是同一回事。调用Dispose时,可以使用using语句,而在别名类型上则使用using指令。
岛之风Skaar

2
万一您想为#1命名(就像您使用三元运算符一样),?? 被称为空合并运算符。
J. Steen

4
@LucasAardvark:正如J Steen提到的,它被称为空合并运算符。搜索!
kokos

1
搜索?? google上的运算符试试:google.com/search?
backslash

103

@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的内部知识,但是我的直觉告诉我,这会将最多两种类型的强制转换操作减少到最多一种。几乎不可能以任何一种方式破坏处理银行。就个人而言,我认为后一种形式看起来也更干净。


16
如果强制类型转换为确切类型(当对象为“ A”而不是从其派生时,投射为“ A”),则直接强制类型转换比“ as”快3倍。强制转换派生类型时(当对象为“ B”且从“ A”派生时,投射到“ A”),直接强制转换比“ as”慢约0.1倍。“是”,那么“ as”只是愚蠢的。
P爸爸

2
不,但是您可以写“ if(((c = obj as MyClass)!= null)”。
Dave Van den Eynde 09年

10
is并且as不会进行用户强制转换。因此,以上代码向is操作员询问obj是否从MyClass派生(或具有隐式系统定义的强制转换)。此外,is失败null。这两种情况对您的代码都可能很重要。例如,您可能要写:if( obj == null || obj is MyClass ) c = (MyClass)obj; 但这与:完全不同:try { c = (MyClass)obj; } catch { }因为前者不会执行任何用户定义的转换,而后者会执行。如果没有null检查,前者也将不设置cobjnull
亚当·卢特

2
在IL中,强制转换转到CASTCLASS,而按原样转到ISINST指令。
约翰·吉布

5
我对此进行了测试,将强制转换IEnumerable<int>List<int>,并将objectnew object())强制转换为IEnumerable<int>,以确保没有错误:直接强制转换:5.43ns,is-> as强制转换:6.75ns,强制转换:5.69ns。然后测试无效的强制转换:直接强制转换:3125000ns,强制转换:5.41ns。结论:不必担心1%的因数,只是确保您使用is / as,当强制转换可能无效时,导致异常(如果也处理)与强制转换相比非常慢,我们正在谈论的是因速57.8万。记住最后一部分,其余部分都没有关系(.Net FW 4.0,发布版本)
Aidiakapi 2011年

98

也许这不是一种先进的技术,但我一直看到的一种使我发疯的方法:

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

可以浓缩为:

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

10
三元运算符已在我的组中被禁止。有些人只是不喜欢它,尽管我从来不知道为什么。
贾斯汀·R。2009年

13
我猜是因为它们不一样,成为运算符而不是陈述。我自己更喜欢第一种方法。它更加一致且易于扩展。运算符不能包含语句,因此必须扩展主体的那一刻,您必须将三元运算符转换为if语句
kervin

16
可以浓缩为x ++; 好吧,这毫无意义^^
弗朗索瓦(François)

5
@Guillaume:要考虑x的所有值:x = 2 + System.Math.Min(1,System.Math.Abs​​(x-1));
mbeckish

38
它实际上是所谓的“有条件的经营者” -这是一个三元运算符,因为它有三个参数。en.wikipedia.org/wiki/Conditional_operator
Blorgbeard将于2009年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.