C#的隐藏特性?

这是我从这个问题中学到以下内容后想到的:

where T : struct

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

我们中的一些人甚至掌握了泛型匿名类型lambdasLINQ等东西。

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

以下是迄今为止透露的特征:


关键字搜索结果

属性

语法

语言功能

Visual Studio功能

框架

方法和性质

提示和技巧

  • Andreas H. R. Nilsson的事件处理程序的不错方法
  • 约翰的大写比较
  • 通过dp访问匿名类型而不进行反射
  • 通过威尔懒惰地实例化集合属性的快速方法
  • 雄酮酸的类似JavaScript的匿名内联函数

其他

742830 次浏览
  1. -合并运算符
  2. 使用(声明/指令)-很好的关键字,可用于不仅仅是调用Disact
  3. 只读应该更多的使用
  4. netmodule-太糟糕了,在Visual Studio中没有支持

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

  1. 片段(特别是对于属性,它在Visual Studio 2008中做得更好)
  2. 废弃属性

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

编译器标记数字是众所周知的:

Decimal = MFloat = FDouble = D
// for exampledouble d = 30D;

然而,这些更模糊:

Long = LUnsigned Long = ULUnsigned Int = U

我有一段时间不知道“as”关键字。

MyClass myObject = (MyClass) obj;

vs

MyClass myObject = obj as MyClass;

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

  • System. Transaction中的TransactionScope和依赖事务类型是在. NET中使用事务处理的轻量级方法-它不仅仅适用于数据库事务
  • String. IsNullOr空是一个我很惊讶地了解到很多开发人员不知道的东西
  • List. Foreach-使用委托方法遍历泛型列表

还有更多,但这是我头顶上的三个明显的…

属性一般,但最重要的是调试参数。节省您的时间。

我倾向于发现大多数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();

返回字符串.空。检查这个链接以获取更多详细信息

我经常遇到需要将一个泛型参数对象持久化到基类的视图状态中。

public abstract class BaseListControl<ListType,KeyType,ParameterType>: UserControlwhere 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);}

这个小技巧与“其中参数类型:基础参数类型,新的”是什么使它真正的工作。

在我的基类中有了这个属性,我可以自动处理分页,设置过滤器值来过滤网格视图,使排序变得非常容易,等等。

我真的只是说仿制药在错误的人手中可能是一只非常强大的野兽。

@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的内部结构知之甚少,无法确定,但我的直觉告诉我,这将把最多两个类型的转换操作减少到最多一个。

还有其他一切

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

void GenericMethod<T>( T input ) { ... }
//Infer type, soGenericMethod<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)Auto属性可以有不同的作用域:

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

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

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

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

@张国荣@张国荣

我认为如果你必须使用Nullable类型,最好使用Nullable<. T>而不是问号符号。它使魔法正在发生的令人震惊的明显。不知道为什么有人会想要使用Nullable<. bool>虽然. :-)

Krzysztof Cwalina(框架设计指南的作者之一)在这里有一个很好的帖子:http://blogs.msdn.com/kcwalina/archive/2008/07/16/Nullable.aspx

Mike Hadlow在无效巫毒上有一个不错的帖子

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

__makeref
__reftype
__refvalue
__arglist

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

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

人们不太了解的一件事是系统名称——一个非常有用的类,它跟踪对象,但仍然允许垃圾收集器收集它。

最有用的“隐藏”功能是产量返回关键字。它并没有真正隐藏,但很多人都不知道它。LINQ构建在此之上;它允许通过在引擎盖下生成状态机来延迟执行查询。Raymond Chen最近发布了关于内在的坚韧不拔的细节的文章。

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

真,假,文件名

没有特别的顺序:

Lists<>Mutex

框架3.5中的新属性定义快捷方式。

避免检查空事件处理程序

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

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

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

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

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

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

如果你有

string s = @"catdogfish"

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

catdogfish

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

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

基于这个线程应该被命名为“直到最近你才知道的关于C#的五件事,尽管你认为你已经知道了一切”,我的个人特性是异步委托。

直到我读了Jeff Richter的C#/CLR书(优秀的书,每个做. NET的人都应该读一读),我才知道你可以使用BeginInvoke/EndInvoke调用任何委托。我倾向于做很多ThreadPool.QueueUserWorkItem调用(我想这很像委托BeginInvoke在内部做的事情),但是添加标准化的连接/会合模式有时可能真的很有用。

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

T t = default(T);

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

lambda表达式

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

模糊字符串格式

Console.WriteLine("{0:D10}", 2); // 0000000002
Dictionary<string, string> dict = new Dictionary<string, string> \{\{"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] );}

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

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

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

能够让枚举类型具有int以外的值(默认值)

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

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

MyEnum e = (MyEnum)123;

CLR通过C#

正规化字符串时,它是高度建议您使用ToUpperInVariant而不是ToLowerInVariant因为微软有优化了代码以执行大写比较。

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

我最喜欢的是

global::

关键字来逃避命名空间地狱与我们的一些第三方代码提供者…

示例:

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

直到最近我才开始真正欣赏“使用”块。它们让事情变得更加整洁:)

这个并不是“隐藏”的,因为它被错误地命名了。

算法“map”、“duce”和“filter”受到了很多关注。大多数人没有意识到的是. NET 3.5添加了所有这三个算法,但它给了它们非常SQL的名字,基于它们是LINQ的一部分这一事实。

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

"duce"=>Aggregate
聚合值到单个结果

"filter"=>其中
过滤数据基于标准

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

从方法返回匿名类型并在没有反射的情况下访问成员。

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

此外,还有ThreadStatic属性使每个线程的静态字段唯一,因此您可以拥有强类型的线程本地存储。

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

//for adding multiple elements to a collection that doesn't have AddRange//e.g., collection.Add(item1, item2, itemN);static void Add<T>(this ICollection<T> 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<Custom>(c=>c.Name,"string",new object(),new Custom())//      result: "string {System.Object} Custom1Name"static string Format<T>(this string format, Func<T,object> 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);}

我认为如果你必须使用nullable类型,最好使用Nullable<. T>而不是问号符号让它看起来很刺眼-很明显魔法正在发生-不是确定为什么会有人想用<. bool>为空

在一个VB.NET的Web服务中,参数可能不会通过(因为合作伙伴的要求不一致或不可靠)传递,但必须通过针对提议的类型(“如果是搜索请求”的布尔值)的验证。

…是的,我知道有些人认为这不是做这些事情的正确方法,但是IsSearchRequest As Nullable(Of Boolean)那天晚上让我失去了理智!

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

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

事件实际上是幕后委托,任何委托对象都可以分别使用+=和-=运算符附加多个函数并与之分离。

事件也可以通过add/删除来控制,类似于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;

它实际上不是C#隐藏功能,但我最近发现了WeakReference类并被它震撼了(尽管这可能是因为它帮助我找到了地雷的具体问题的解决方案…)

我必须承认,我不确定这执行更好或更差的比正常的ASP.NET中继器onItem数据库投代码,但无论如何,这是我的5美分。

MyObject obj = e.Item.DataItem as MyObject;if(obj != null){//Do work}

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

几乎所有很酷的都被提到了。不确定这个是否众所周知

C#属性/字段构造函数初始化:

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

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

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

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

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

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

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

public string Name { get; private set;}

这样,只有类本身可以设置Name属性。

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

Rick Strahl

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

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

部分方法

查理·卡尔弗特在他的博客上解释了部分方法

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

  1. 代码生成类中的可扩展性点(LINQ toSQL, EF)
  2. 如果未实现,则不会编译到dll中(使用. NET Reflector检查)

也许不是一个先进的技术,但一个我看到所有的时间,让我发疯:

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

可以浓缩为:

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

如果您希望在调试和发布模式之间有不同的行为,预处理器指令可以很漂亮。

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

我看到很多人复制Nullable<T>.GetValueOrDefault(T)的功能。

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

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

枚举上的标志属性怎么样?它允许您执行按位操作……我花了很长时间才找到如何在. NET中很好地执行按位操作。

我很确定每个人都熟悉操作符重载,但也许有些人不是。

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#语言是在不同的时间编写的,因此不一致。例如,框架本身违反了许多FxCop规则,因为在编写框架时规则并未全部到位。

此外,使用语句是为了划分“作用域”,而不是专门用于处理资源。它是在lock语句之后编写的。Eric Gunnerson曾经提到大致是这样的,如果使用语句首先出现,他们可能不需要编写lock语句(尽管谁知道,也许他们无论如何都会写),因为使用语句可能已经足够了。

@陈志强,

当从数据库中检索可为空的值以及将值放回时,可为空的布尔值很有用。有时您想知道该字段尚未设置。

在阅读关于. NET框架开发的书时,一个很好的建议是不要使用bool来打开或关闭东西,而是使用ENum。

使用ENum,您可以为自己提供一些可扩展性,而无需重写任何代码来向函数添加新功能。

C#?? null合并运算符-

不是真的隐藏,但很少使用。可能是因为很多开发人员看到条件?运算符时会跑一英里,所以当他们看到这个运算符时会跑两个。使用:

string mystring = foo ?? "foo was null"

而不是

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

Lambdas可以有多个语句和它们双作为兼容的委托对象自动(只要确保签名匹配),如:

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

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

Lambdas不需要归还任何东西和类型推断在这样的上下文中非常强大。

顺便说一句,你总是可以在函数式编程意义上返回制造Lambdas的Lambdas。例如,这是一个lambda,它生成了一个处理Button. Click事件的lambda:

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

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

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

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

反射发射和表达式树浮现在脑海中…

不要错过Jeffrey Richter的C#CLR和Jon Skeet的alt text

在这里查看一些资源:

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

#如果调试预处理器指令。它对测试和调试(尽管我通常更喜欢去单元测试路线)。

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

只有在Visual Studio设置为以“调试”模式编译。否则代码块将被被编译器忽略(并在Visual Studio中变灰)。

我参加这个派对迟到了,所以我的第一个选择已经有人了。但是我还没有看到有人提到这个宝石:

. NET Framework的并行扩展

它有一些东西,比如用Parallel. For替换或用Parallel. For每个替换


并行示例:
在你看来,一秒钟可以创建多少个CLR对象?enter image description here
参见休耕示例:

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<Task>();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 tasksTask.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);}}}

真正虚假操作符真的很奇怪。

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

编辑:有相关的SO问题什么是C#中的假运算符?

返回IQueryable投影

protected void LdsPostings_Selecting(object sender, LinqDataSourceSelectEventArgs e){var dc = new MyDataContext();var query = dc.Posting.AsQueryable();
if (isCondition1){query = query.Where(q => q.PostedBy == Username);e.Result = QueryProjection(query);return;}
...
if (isConditionN){query = query.Where(q => q.Status.StatusName == "submitted");query = query.Where(q => q.ReviewedBy == Username);e.Result = QueryProjection(query);return;}}

而不是多次编码投影,创建一个方法:

private IQueryable QueryProjection(IQueryable<Posting> query){return query.Select(p => new{p.PostingID,p.Category.CategoryName,p.Type.TypeName,p.Status.StatusName,p.Description,p.Updated,p.PostedBy,p.ReviewedBy,});}

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

string sql = @"SELECT firstname, lastname, emailFROM usersWHERE username = @username AND password = @password";

考虑了一下@刘德华并决定尝试一下。这是我想出的可能对一些人有用的东西:

// using the concepts of dp's AnonCaststatic Func<T> TypeCurry<T>(Func<object> 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)};}

我喜欢在列表中查找东西,例如:-

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

在实践中没有出现那么多,但是根据搜索主题匹配项目的想法可能非常有用+简洁。

系统诊断命名空间中的几个其他属性非常有用。

调试工具将允许您从调试器窗口隐藏变量(我们将其用于暴露属性的所有私有后备变量)。除此之外,逐步调试器使调试器跨过该代码,对哑属性非常有用(如果您可以对C#3.0编译器进行依赖,可能应该转换为自动属性)。作为一个例子

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

条件属性

允许您告诉编译器在某些条件下省略对标记有属性的方法的调用(#定义)。

省略方法调用的事实也意味着它的参数不会被评估。这非常方便,它允许您在Debug. Aste()中调用昂贵的验证函数,而不必担心它们会减慢您的发布构建速度。

Environment.NewLine

对于系统独立的换行符。

使用语句嵌套

通常我们是这样做的:

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)) {...}

外部别名关键字引用具有相同完全限定类型名称的程序集的两个版本。

PreviousPage属性:

"System.Web.UI.页面,表示将控制权转移到当前页面的页面。"

它非常有用。

在验证用户输入时,每个基元类型的TryParse方法都很棒。

double doubleValueif (!Double.TryParse(myDataRow("myColumn"), out doubleValue)){// set validation error}

Foreach使用鸭子打字

转述,或者无耻地从Krzysztof Cwalinas博客中窃取这一点。比任何事情都更有趣的琐事。

为了让你的对象支持foreach,你不要必须实现可数。也就是说,这不是一个约束,也不是编译器检查的。检查的是

  • 您的对象提供了一个公共方法获取分子类型
    • 不带参数
    • 返回一个有两个成员的类型
      1. 返回一个布尔值的无参数方法MoveNext
      2. 物业当前返回一个对象的getter

例如,

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!");}

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

  • __makeref
  • __reftype
  • __refvalue
  • __arglist

使用示例:

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

@@张一鸣

但是我的直觉告诉我最多能切两种类型的石膏#36825;的最大值为1”

如果你按照示例1中的建议进行转换(使用is&as),它会导致对“is”运算符的2次调用。因为当你做“c=obj as MyClass”时,它首先在幕后调用“is”,然后如果失败,它只是返回null。

如果你按照你在例子2中建议的那样做,

c = (MyClass)obj

然后这实际上再次执行“is”操作,然后如果检查失败,它会抛出异常(InvalidCastException)。

所以,如果你想做一个轻量级的动态转换,最好做你提供的第三个例子:

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

vs

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

你可以看到哪个更快,更清楚,更清晰。

@大卫在达科他州:

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

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

new String('-',22);

内部查看属性是一个不太为人所知的属性,但在某些情况下可以非常方便。它基本上允许另一个程序集能够访问定义程序集的“内部”元素。

我今天才知道这个——我已经使用C#工作了5年!

这是命名空间别名限定符

extern alias YourAliasHere;

您可以使用它来加载同一类型的多个版本。这在维护或升级场景中很有用,在这些场景中,您的类型的更新版本在某些旧代码中不起作用,但您需要将其升级到新版本。点击命名空间别名限定符,编译器会让您在代码中同时拥有这两种类型。

我喜欢关键字继续

如果你在循环中遇到一个条件,并且除了推进循环之外不想做任何事情,只需坚持“继续;”。

例如:

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

不是C#特定的东西,但我是一个三元操作迷。

而不是

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

你可以使用简洁

booleanCondtion ? true operation : false operation;

e. g.

而不是

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

你可以输入

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

它确实有助于编写简洁的代码,但嵌套该死的东西可能很讨厌,它们可能被用于邪恶,但我仍然喜欢小吸盘

看到上面提到的List. For每个;2.0引入了一系列基于谓词的集合操作——查找、FindAll、存在等,再加上匿名委托,您几乎可以实现3.5的lambda表达式的简单性。

有几件事我喜欢:

-如果您创建类似于

 public interface SomeObject<T> where T : SomeObject<T>, new()

你强制从这个接口继承的任何东西包含一个无参数构造函数。它对于这是我遇到的一些问题

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

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

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

public synchronized void MySynchronizedMethod(){}

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

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

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

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

给定这个类:

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

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

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

好吧,这很糟糕,因为缺乏强类型。如果我重命名“某些方法”怎么办?现在,在3.5中,我可以以强类型的方式执行此操作:

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

在这个例子中,注册方法类使用Expression<Action<T>>,如下所示:

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

这是我现在爱上Lambdas和表达式树的一个重要原因。

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

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

易失性关键字告诉编译器一个字段可以被多个线程同时修改。

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

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;}
  1. 我还不能发表评论,但请注意,默认情况下,Visual Studio 2008会自动遍历属性,因此在这种情况下不再需要DebuggerStep的属性。

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

    () => DoSomething(x);

你还应该阅读闭包——我不够聪明,无法正确解释它们。但基本上,这意味着编译器做了聪明的事情,这样该行代码中的x即使在创建lambda后“超出范围”也仍然可以工作。

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

    (e, _) => DoSomething(e)

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

System. Runtime. Remting. Proxy

它支持C#中的面向方面编程,您还可以用它做很多其他花哨的事情。

别名泛型:

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

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

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

新的修饰语

在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"}}

[Ed:双关语有加分吗?抱歉,没办法。]

不要忘记goto

通过switch-case可以通过在case中没有代码(见case 0)或使用特殊的goto case(见case 1)或goto default(见case 2)形式来实现:

switch (/*...*/) {case 0: // shares the exact same code as case 1case 1:// do somethinggoto case 2;case 2:// do something elsegoto default;default:// do something entirely differentbreak;}

对于分组代码(大纲)来说,#区域{string}和#终端区域对非常简洁。

#region Using statementsusing System;using System.IO;using ....;using ....;#endregion

代码块可以压缩为单个描述文本行。也适用于函数内部。

静态构造函数。

实例:

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,并且您无法向下钻取到违规的代码行。相反,您必须检查TypeInitializationExceptionInnerException成员,这是具体原因。

BCL中的一些并发实用程序可能符合隐藏功能的条件。

像System. Thread. Monitor这样的东西在内部由lock关键字使用;显然在C#中,lock关键字是首选的,但有时知道如何在较低级别完成工作是值得的;我必须锁定C++ /CLI,所以我用调用Monitor. enter()和Monitor. Exit()来封装代码块。

文字可以用作该类型的变量。例如。

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 exceptionConsole.ReadLine();}

在lambda发挥作用之前,它是匿名委托。这可以用于类似于Ruby的块给定的总括代码。我还没有测试lambda是如何工作的,因为到目前为止我想坚持使用. NET 2.0。

例如,当您想确保记得关闭超文本标记语言标记时:

MyHtmlWriter writer=new MyHtmlWriter();writer.writeTag("html",delegate (){writer.writeTag("head",delegate(){writer.writeTag("title"...);})})

我相信如果lambda是一个选项,它可以产生更干净的代码:)

如果允许第三方扩展,那么C5microsoftccr(参见这篇博客文章的快速介绍)是必须知道的。

C5补充。Net有点缺乏集合库(不是Set???),CCR使并发编程更容易(我听说它将与并行扩展合并)。

TryGetValue(K键,输出V值)

既是一种支票,也是一种进入。

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

你可以只做;

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

值已设置。

我想很多人都知道C中的指针,但不确定它是否在C#中有效。您可以在不安全的上下文中使用C#中的指针:

static void Main(){int i;unsafe{// pointer pi has the address of variable iint* pi = &i;// pointer ppi has the address of variable piint** ppi = &pi;// ppi(addess of pi) -> pi(addess of i) -> i(0)i = 0;// dereference the pi, i.e. *pi is iConsole.WriteLine("i = {0}", *pi); // output: i = 0// since *pi is i, equivalent to i++(*pi)++;Console.WriteLine("i = {0}", *pi); // output: i = 1// since *ppi is pi, one more dereference  *pi is i// equivalent to i += 2**ppi += 2;Console.WriteLine("i = {0}", *pi);// output: i = 3}Console.ReadLine();}

有些奇怪:)

Delegate target =(target0 = target as CallTargetWithContext0) ??(target1 = target as CallTargetWithContext1) ??(target2 = target as CallTargetWithContext2) ??(target3 = target as CallTargetWithContext3) ??(target4 = target as CallTargetWithContext4) ??(target5 = target as CallTargetWithContext5) ??((Delegate)(targetN = target as CallTargetWithContextN));

有趣的是注意到由于某种原因需要的最后一个演员。错误还是设计?

System.Diagnostics.Debug.Assert (false);

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

有一些运算符用于在声明的类和一个或多个任意类之间执行#0#1用户定义的类型转换。implicit运算符有效地允许模拟重载赋值运算符,这在C++等语言中是可能的,但在C#中不行。

它似乎不是经常遇到的功能,但实际上它在LINQ到XMLSystem.Xml.Linq)库中使用,您可以在其中隐式将字符串转换为XName对象。示例:

XName tagName = "x:Name";

我在这个文章中发现了这个关于如何在C#中模拟多重继承的特性。

联合(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);}

输出这个:

2147483647FF FF FF 7F65535

添加使用System. Runtime. InteropServices;

我遇到的一些隐藏功能:

  • stackalloc允许您在堆栈上分配数组
  • 没有显式参数列表的匿名方法,可隐式转换为具有非out/ref参数的任何委托类型(对于事件非常方便,如前面的注释所述)
  • 很多人不知道事件到底是什么(添加/删除方法对,如属性的get/set);C#中的类似字段的事件实际上既声明了变量又声明了事件
  • 可以重载==!=运算符以返回bool以外的类型。奇怪但真实。
  • C#3中的查询表达式翻译在某些方面非常“简单”-这意味着您可以让它做一些非常奇怪的事情
  • 可空类型具有特殊的装箱行为:空值被装箱为空引用,您也可以将空值拆箱为可空类型。

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

[AttributeUsage( AttributeTargets.ReturnValue )]public class CuriosityAttribute:Attribute{}
public class Bar{[return: Curiosity]public Bar ReturnANewBar(){return new Bar();}}

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

字符串实习。这是我在这次讨论中还没有看到的一个。它有点模糊,但在某些条件下它可能是有用的。

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

您可以使用字符串。被嵌入(字符串)来测试字符串是否被实习,也可以使用字符串。实习生(字符串)来实习字符串。

备注: CLR可以在应用程序甚至AppDomain结束后保存对内部字符串的引用。有关详细信息,请参阅MSDN留档。

params关键字,即。

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

打电话给

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

标记我的末端区域…

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

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

隐式方法组转换

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

查看“C#中的隐式方法组转换”了解更多。

我喜欢有一个静态整数解析函数,当它无法解析时返回null,而不是使用int. TryParse()或Conversion. ToInt32()。然后我可以一起使用??和三元运算符来更清楚地确保我的声明和初始化都以易于理解的方式在一行上完成。

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-that树(我经常遇到):

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

更清晰,更容易理解

环境。用户交互属性。

UserInteractive属性报告为Windows进程或像IIS这样的服务在没有用户交互界面。如果此属性是false,不显示模式对话框或消息框,因为没有图形用户交互界面#36825;互动

上下文边界对象

与其说是C#的东西,不如说是. NET的东西。这是实现DI的另一种方式,尽管它可能是艰苦的工作。你必须继承它,这可能会令人讨厌。

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

当我使用自定义日志记录属性装饰类/方法时,我使用它来添加日志记录。

完全访问调用堆栈:

public static void Main(){StackTrace stackTrace = new StackTrace();           // get call stackStackFrame[] stackFrames = stackTrace.GetFrames();  // get method calls (frames)
// write call stack method namesforeach (StackFrame stackFrame in stackFrames){Console.WriteLine(stackFrame.GetMethod().Name);   // write method name}}

因此,如果您选择第一个-您知道自己在哪个函数中。如果您正在创建一个辅助跟踪函数-在最后一个之前采取一个-您将知道您的调用者。

在使用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;}

如果你想退出你的程序而不调用任何最终块或终结器,请使用失败方式

Environment.FailFast()
double dSqrd = Math.Pow(d,2.0);

double dSqrd = d * d; // Here we can lose precision

你可以打开弦!

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

非常方便!比一堆if-有助语句要干净得多

刚刚了解到,匿名类型可以从变量名推断属性名:

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

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

<configuration><runtime><gcServer enabled="true"/></runtime></configuration>

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

对于数据库应用程序开发人员来说,这可能是非常基本的,但我花了一段时间才意识到null与DBNull.value.不一样

当您想查看数据库记录中的值是否为空时,必须使用DBNull.value。

对象的引用等于方法

确定指定的Object实例是否为同一实例。

参数:

  • Object:System. Object-要比较的第一个对象。
  • Object:System. 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. ReReference ceEquals()方法总是比较引用。尽管类可以为等号操作符提供自己的行为(如下),如果调用运算符,则不会调用重新定义的运算符通过对System. Object的引用。

对于字符串,实际上并没有区别,因为==和Equals都被覆盖以比较字符串的内容。

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

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

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

当然,一些清晰度被牺牲了。但它奏效了!

线程静态属性是我的最爱。此外,NonSerializableAt的是有用的。(你能告诉我做了很多服务器的东西使用远程?)

泛型事件处理程序:

public event EventHandler<MyEventArgs> MyEvent;

通过这种方式,您不必一直声明自己的代表,

刚刚学会了[UnmanagedFunctionPointerAttribute(CallingConvention.CDecl)]的乐趣,尝试与非托管C++函数库接口,该函数库定义了回调而没有__stdcall。

在将近一年的时间里,我没有发现强类型DataRow包含一个Is[LaynName]Null()方法。

例如:

Units.UnitsDataTable dataTable = new Units.UnitsDataTable();
foreach (Units.UnitsRow row in dataTable.Rows){if (row.IsPrimaryKeyNull())//....
if (row.IsForeignKeyNull())//....}

Math. Max和Min检查边界:我在很多代码中看到过这个:

if (x < lowerBoundary){x = lowerBoundary;}

我发现这个更小,更清晰,更可读:

x = Math.Max(x, lowerBoundary);

或者你也可以使用三元运算符:

x = ( x < lowerBoundary) ? lowerBoundary : x;

我错过了很长一段时间:您可以将字符串与

进行比较
"string".equals("String", StringComparison.InvariantCultureIgnoreCase)

而不是做:

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

Mixins是一个很好的特性。基本上,Mixins让你为接口而不是类拥有具体代码。然后,只需在一堆类中实现接口,你就会自动获得Mixin功能。例如,要将深度复制混合到几个类中,请定义一个接口

internal interface IPrototype<T> { }

添加此接口的功能

internal static class Prototype{public static T DeepCopy<T>(this IPrototype<T> 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;}}

然后实现任何类型的接口以获得混合。

ViewState getter可以是单行的。

使用默认值:

public string Caption{get { return (string) (ViewState["Caption"] ?? "Foo"); }set { ViewState["Caption"] = value; }}
public int Index{get { return (int) (ViewState["Index"] ?? 0); }set { ViewState["Index"] = value; }}

使用null作为默认值:

public string Caption{get { return (string) ViewState["Caption"]; }set { ViewState["Caption"] = value; }}
public int? Index{get { return (int?) ViewState["Index"]; }set { ViewState["Index"] = value; }}

这适用于任何由字典支持的东西。

关于foreach:它不使用“鸭子类型”,因为鸭子类型IMO指的是运行时检查。它在编译时使用结构型式检验(而不是标称)来检查类型中所需的方法。

这是一个提示如何使用#区域指令来记录代码。

(我只是用了这个)设置一个字段null并返回它,没有中间变量:

try{return _field;}finally{_field = null;}

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

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

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

我不确定我对C#支持赋值表达式的感觉如何,但是嘿,它就在那里:-)

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

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

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

您可以在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!";}}

如何使用这个:

#if DEBUGConsole.Write("Debugging");#elseConsole.Write("Final");#endif

当您使用定义的DEBUG编译解决方案时,它将输出“调试”。

如果您的编译设置为发布,它将写入“Final”。

框架功能

我不知道,但我对可视化样式渲染器和整个System. Windows. Forms. Visual Styles-命名空间感到非常惊讶。很酷!

IEnumerableSelectMany,它将列表展平为一个列表。假设我有一个Orders的列表,每个Order都有一个按顺序排列的LineItems的列表。

我想知道LineItems的总销量…

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

这不是C#特定的类型,但我刚刚找到了ISurroogateSelector和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

将它们与BinaryFor物质结合使用允许通过代理类的实现对不可序列化的对象进行序列化。代理模式在计算机科学中得到了很好的理解,特别是在处理序列化问题时。我认为这个实现只是作为BinaryFor的构造函数的参数隐藏起来,这太糟糕了。

非常隐蔽:)

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

例如:

  • Action<int>是一个委托方法,它接受单个int参数并返回false。
  • Func<int>是一个委托方法,不接受任何参数并返回一个int。
  • Func<int, bool>是一个委托方法,它接受一个int参数并返回一个bool。

这些特性是在. NET框架的3.5版中引入的。

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

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

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

其他未充分使用的运算符是checkedunchecked

short x = 32767;   // 32767 is the max value for shortshort y = 32767;int z1 =  checked((short)(x + y));   //will throw an OverflowExceptionint z2 =  unchecked((short)(x + y)); // will return -2int z3 =  (short)(x + y);            // will return -2

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

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()调用基类的方法

C#4.0中的动态关键字

如果您希望您的方法调用仅在运行时解析,您可以使用动态关键字。

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

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

static void Main(string[] args){var domain = "matrix";Check(() => domain);Console.ReadLine();}
static void Check<T>(Expression<Func<T>> 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#中找出变量或参数名称?

这不是C#特有的功能,但我发现它是一个非常有用的插件。它被称为资源重构工具。它允许您右键单击文字字符串并将其解压缩到资源文件中。它将搜索代码并找到任何其他匹配的文字字符串,并将其替换为Resx文件中的相同资源。

http://www.codeplex.com/ResourceRefactoring

List<T>的TrueForAll方法:

List<int> s = new List<int> { 6, 1, 2 };
bool a = s.TrueForAll(p => p > 0);

关闭

自从匿名委托被添加到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<Action> setAndTagChanged = (action) =>{changed = true;action();};
if (model.Prop1 != prop1) setAndTagChanged(() => model.Prop1 = prop1);if (model.Prop2 != prop2) setAndTagChanged(() => model.Prop2 = prop2);

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

另一种方法是使用另一种未使用的功能,即“或等于”二进制赋值操作符。

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

我称之为AutoDebug,因为您可以根据bool值直接进入调试,该值也可以存储为项目用户设置。

示例:

//Place at top of your codepublic UseAutoDebug = true;

//Place anywhere in your code including catch areas in try/catch blocksDebug.Assert(!this.UseAutoDebug);

只需将上述内容放在try/catch块或代码的其他区域中,并将UseAutoDebug设置为true或false,然后随时进入调试。

您可以保留此代码,并在测试时打开和关闭此功能,您还可以将其保存为项目设置,并在部署后手动更改它,以便在需要时从用户那里获取其他bug信息。

您可以在此处的Visual Studio C#项目模板中看到使用此技术的功能和工作示例,其中大量使用:

http://code.msdn.microsoft.com/SEHE

C一个la.0的LINQ查询理解是成熟的一元理解一个la Haskell(实际上它们是由Haskell的一位设计者设计的)。它们适用于任何遵循“LINQ模式”的泛型类型,并允许您以纯一元函数风格编写,这意味着您的所有变量都是不可变的(就好像您使用的唯一变量是使用Foreach语句中的IDisposableIEnumerable一样)。这有助于将变量声明保持在使用它们的地方附近,并确保显式声明所有副作用(如果有的话)。

 interface IFoo<T>{ T Bar {get;}}
class MyFoo<T> : IFoo<T>{ public MyFoo(T t) {Bar = t;}public T Bar {get; private set;}}
static class Foo{ public static IFoo<T> ToFoo<T>(this T t) {return new MyFoo<T>(t);}
public static void Do<T>(this T t, Action<T> a) { a(t);}
public static IFoo<U> Select<T,U>(this IFoo<T> foo, Func<T,U> 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 filein Foo monad if necessary */});
}

我想说,使用某些系统类的扩展方法是非常方便的,例如System. Enum,你可以像下面这样做…

[Flags]public enum ErrorTypes : int {None = 0,MissingPassword = 1,MissingUsername = 2,PasswordIncorrect = 4}
public static class EnumExtensions {
public static T Append<T> (this System.Enum type, T value) where T : struct{return (T)(ValueType)(((int)(ValueType) type | (int)(ValueType) value));}
public static T Remove<T> (this System.Enum type, T value) where T : struct{return (T)(ValueType)(((int)(ValueType)type & ~(int)(ValueType)value));}
public static bool Has<T> (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 methodsif (error.Has(ErrorTypes.MissingUsername)) {...}

当然,这只是一个例子-这些方法可能需要更多的工作…

您可以在非泛型类中拥有泛型方法。

在使用lambdas时模拟功能性“通配符”参数(如Haskell中的“_”)的很酷的技巧:

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

仅用于引用-使用扩展方法的枚举二进制操作。

using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Linq.Expressions;
namespace BinaryOpGenericTest{[Flags]enum MyFlags{A = 1,B = 2,C = 4
}
static class EnumExtensions{private static Dictionary<Type, Delegate> m_operations = new Dictionary<Type, Delegate>();
public static bool IsFlagSet<T>(this T firstOperand, T secondOperand)where T : struct{
Type enumType = typeof(T);

if (!enumType.IsEnum){throw new InvalidOperationException("Enum type parameter required");}

Delegate funcImplementorBase = null;m_operations.TryGetValue(enumType, out funcImplementorBase);
Func<T, T, bool> funcImplementor = funcImplementorBase as Func<T, T, bool>;
if (funcImplementor == null){funcImplementor = buildFuncImplementor(secondOperand);}


return funcImplementor(firstOperand, secondOperand);}

private static Func<T, T, bool> buildFuncImplementor<T>(T val)where T : struct{var first = Expression.Parameter(val.GetType(), "first");var second = Expression.Parameter(val.GetType(), "second");
Expression convertSecondExpresion = Expression.Convert(second, typeof(int));var andOperator = Expression.Lambda<Func<T, T, bool>>(Expression.Equal(Expression.And(Expression.Convert(first, typeof(int)),convertSecondExpresion),convertSecondExpresion),new[] { first, second });Func<T, T, bool> andOperatorFunc = andOperator.Compile();m_operations[typeof(T)] = andOperatorFunc;return andOperatorFunc;}}

class Program{static void Main(string[] args){MyFlags flag = MyFlags.A | MyFlags.B;
Console.WriteLine(flag.IsFlagSet(MyFlags.A));Console.WriteLine(EnumExtensions.IsFlagSet(flag, MyFlags.C));Console.ReadLine();}}}

方法组并不为人所知。

给定:

Func<Func<int,int>,int,int> myFunc1 = (i, j) => i(j);Func<int, int> myFunc2 = i => i + 2;

你可以这样做:

var x = myFunc1(myFunc2, 1);

而不是这个:

var x = myFunc1(z => myFunc2(z), 1);

您可以使用泛型来检查(编译时)方法参数是否实现了两个接口:

interface IPropA{string PropA { get; set; }}
interface IPropB{string PropB { get; set; }}
class TestClass{void DoSomething<T>(T t) where T : IPropA, IPropB{MessageBox.Show(t.PropA);MessageBox.Show(t.PropB);}}

从基类和接口继承的参数也是如此。

构造函数链是否已经引用?

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

不是隐藏的,但很简洁。我发现这是一个更简洁的替代简单的如果-然后-否则,只是根据条件分配一个值。

string result =i < 2 ?               //question"less than 2" :       //answeri < 5 ?               //question"less than 5":         //answeri < 10 ?              //question"less than 10":       //answer"something else";     //default answer

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

Microsoft.VisualBasic.Logging.FileLogTraceListener

MSDN链接

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

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

使用枚举。

将字符串转换为枚举:

enum MyEnum{FirstValue,SecondValue,ThirdValue}
string enumValueString = "FirstValue";MyEnum val = (MyEnum)Enum.Parse(typeof(MyEnum), enumValueString, true)
  • 我使用它从数据库中的设置表加载ASP.NET应用程序中CacheItemPriality的值,以便我可以动态控制缓存(以及其他设置),而无需关闭应用程序。

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

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

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

public void DoStuff<T>(T value);

而不是像这样称呼它:

DoStuff<int>(5);

您可以:

DoStuff(5);

它将从参数的类型中计算出泛型类型。

  • 如果您通过反射调用该方法,这将不起作用。
  • 我记得在Mono上有一些奇怪的问题。

许多人没有意识到他们可以使用:普通IgnoreCase来比较字符串,而不必做一些String. ToUper()。这消除了额外的字符串分配开销。

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

成为

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

我最喜欢的属性:内部显示

在程序集级别,您可以声明另一个程序集可以看到您的内部。出于测试目的,这绝对很棒。

将其粘贴在您的AssemblyInfo.cs或等效程序中,您的测试程序集就可以完全访问需要测试的所有内部内容。

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

如您所见,测试程序集必须具有一个坚强的名字才能获得被测试程序集的信任。

可在. Net Framework 2.0+、Compact Framework 2.0+和XNA Framework 1.0+中使用。

固定/C#中指针的力量-这个主题太大了,但我只会概述一些简单的事情。

在C中,我们有加载结构的设施,如…

struct cType{char type[4];int  size;char name[50];char email[100];}
cType myType;fread(file, &mType, sizeof(mType));

我们可以在“不安全”方法中使用固定关键字来读取字节数组对齐结构。

[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(从常规流读取到字节缓冲区并将字节数组映射到结构的单个字节)

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<buffer.Length;i++){(*bsp) = (*bp);bsp++;bp++;}}}

方法二,可以将Win32User32.dll的ReadFile映射为直接读取字节…

CType mType = new CType();fixed(CType* p = &mType){User32.ReadFile(fileHandle, (byte*) p, Marshal.SizeOf(mType),0);}

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

public class GenericList<T>{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;}}

另一个例子

InternalsVisibleToAtame指定通常仅在当前程序集中可见的类型对另一个程序集可见。关于msdn的文章

而不是像这样做一些俗气的事情:

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

我使用以下内联技巧:

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

当有一项时,这将显示“项目”,当有多于(或少于)1时,这将显示“项目”。

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

当我使用自上而下的方法作为“待办事项”列表进行开发时,我通常使用这些。我将#error Implement this function#warning Eventually implement this corner case作为提醒。

在处理C++和C#之间的互操作时,许多人没有意识到C++ /CLI是一个很好的选择。

假设您有一个C++DLL和一个依赖于C++DLL的C#DLL。通常,最简单的技术是用 /clr开关编译C++DLL的一些(或所有)模块。让C#调用C++DLL就是在C++DLL中编写托管C++包装类。C++ /CLI类可以比C#更无缝地调用本机C++代码,因为C++编译器会自动为您生成P/调用,有一个专门用于互操作的库,以及pin_ptr等互操作的语言功能。它允许托管和本机代码在同一个二进制文件中共存。

在C#端,您只需像调用任何其他. NET二进制文件一样调用DLL。

我对这个问题已经很晚了,但我想添加一些我认为还没有涵盖的内容。这些不是特定于C#的,但我认为对于任何C#开发人员来说,它们都值得一提。

环境值属性

这类似于DefaultValueAttribute,但它不是提供属性默认的值,而是提供属性用来决定是否从其他地方请求其值的值。例如,对于WinForms中的许多控件,它们的ForeColorBackColor属性具有Color.Empty中的AmbientValue,以便它们知道从父控件获取它们的颜色。

隔离存储设置

这是一个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会让这更容易。

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

    void FileMessageEvent(object sender, MessageEventArgs e){
if (this.InvokeRequired == true){this.BeginInvoke((MethodInvoker)delegate {lblMessage.Text=e.Message;Application.DoEvents();});
}}

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

我发现编译器在使用外部变量时遇到了什么样的麻烦令人难以置信:

string output = "helo world!";Action action = () => Console.WriteLine(output);output = "hello!";action();

这实际上打印了hello!。为什么?因为编译器为委托创建了一个嵌套类,所有外部变量都有公共字段,并在每次调用委托之前插入seting-code:)这是上面的代码“反射”:

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.<Main>b__0);CS$<>8__locals2.output = "hello!";action();

我觉得很酷。

我无法弄清楚Convert类中的一些函数有什么用处(例如Convert. ToDouble(int)、Convert. ToInt(Double)),直到我将它们与Array.ConvertAll组合在一起:

int[] someArrayYouHaveAsInt;double[] copyOfArrayAsDouble = Array.ConvertAll<int, double>(someArrayYouHaveAsInt,new Converter<int,double>(Convert.ToDouble));

它避免了定义内联委托/闭包所产生的资源分配问题(并且更具可读性):

int[] someArrayYouHaveAsInt;double[] copyOfArrayAsDouble = Array.ConvertAll<int, double>(someArrayYouHaveAsInt,new Converter<int,double>(delegate(int i) { return (double)i; }));

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

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

好吧…别用它,但是很多人不知道C#支持邪恶的goto:)

static void Example(){int i = 0;top:Console.WriteLine(i.ToString());if (i == 0){i++;goto top;}}

刚刚了解了不变性、协方差和逆变的含义,我发现了将包含在. NET 4.0中的泛型修饰符。它们看起来很晦涩,以至于大多数程序员都不知道它们。

在Visual Studio杂志上有一个文章,它讨论了这些关键字以及如何使用它们。

目标

每个人都见过。基本上,当你看到这个:

[assembly: ComVisible(false)]

该属性的“汇编:”部分是目标。在这种情况下,该属性应用于程序集,但还有其他:

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

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

如果您想阻止垃圾收集器运行对象的终结器,只需使用GC.SuppressFinalize(object);。类似地,GC.KeepAlive(object);将通过引用该对象来阻止垃圾收集器收集该对象。不是很常用,至少根据我的经验,但很高兴知道以防万一。

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

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

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

当仔细使用时,重新选择是如此强大。我在一个电子邮件模板系统中使用它。模板管理器将被传递一个对象,而html模板将嵌入引用属性的字段,这些字段可以使用反射从传递的对象中检索。工作得非常好。

当与. NET 3.5中的语句lambdas一起使用时,绝对是Func<>类型。这些允许可定制的函数,并且可以很好地帮助为用户提供可定制的对象,而无需对它们进行子类化或诉诸一些有限的系统,例如跟踪列出用户想要监控的按钮或键的变量。此外,它们可以像常规方法一样调用,并且可以像变量一样分配。我能想到的唯一缺点是你被限制为5个参数!虽然到那时你可能想考虑不同的解决方案…编辑:提供一些示例。

...public Func<InputHelper, float> _horizontalCameraMovement = (InputHelper input) =>{return (input.LeftStickPosition.X * _moveRate) * _zoom;}public Func<InputHelper, float> _verticalCameraMovement = (InputHelper input) =>{return (-input.LeftStickPosition.Y * _moveRate) * _zoom;}...public void Update(InputHelper input){...position += new Vector2(_horizontalCameraMovement(input), _verticalCameraMovement(input));...}

在此示例中,您可以编写一个执行任意计算并返回一个浮点数的函数,该浮点数将确定相机移动的量。不是最好的代码,但它得到了要点。

private int foo;public int FooProperty {get{if (_onFooGotten() == true)return _foo;}set{if (onFooSet() == true)_foo = value;}}...public Func<bool> _onFooGotten = () =>{//do whatever...return true;}public Func<bool> _onFooSet = () =>{//do whatever...return true;}

这不是最好的例子(因为我还没有真正探索过这种用法),但它展示了一个使用lambda函数进行快速事件引发器的例子,而不需要委托。编辑:想到另一个。空值!C#最接近可选参数的东西。

FlagsAt的,一个小但不错的功能当使用枚举来做一个位掩码:

[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

如果在Visual Studio工具栏中有搜索文本框,则可以键入“>ofProgram.cs”来打开文件Program.cs

可以为枚举定义数据类型:

enum EnumName : [byte, char, int16, int32, int64, uint16, uint32, uint64]{A = 1,B = 2}

我的一些-让他们成为你想要的。

属性:

[assembly::InternalsVisibleTo("SomeAssembly")]

允许您将程序集中的内部方法/属性或数据公开给另一个名为“某些程序集”的程序集。所有受保护/私有的东西都保持隐藏状态。


静态构造函数(也称为“类型构造函数”)

public MyClass{public static MyClass(){// type init goes here}......}

关键字internal。在很多方面都很有用。

高级调试

显示

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

如果你想要更复杂的输出,你可以使用/创建一个调试器可视化工具,几个例子这里.

罢工之子

Microsoft提供了一个名为SOS的调试器扩展。这是一个非常强大(尽管经常令人困惑)的扩展,它是诊断“泄漏”的绝佳方法,更准确地说,是对不再需要的对象的不需要的引用。

框架源代码的符号服务器

遵循这些说明将允许您逐步了解框架某些部分的源代码。

2010年的变化

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

  • 调试并行任务
  • 并行堆栈允许同时查看多个线程调用堆栈。
  • 历史调试可以让您及时查看事件和非局部变量(只要您提前启用集合)。可能会对调试方式产生重大变化。

使用“抛出;”而不是“抛出ex;”来保留堆栈跟踪

如果在不添加额外信息的情况下重新抛出异常,请使用“抛出”而不是“抛出ex”。catch块中的空“抛出”语句将发出特定的IL,该IL在保留原始堆栈跟踪的同时重新抛出异常。“抛出ex”会丢失异常原始源的堆栈跟踪。

能够基于这样的泛型参数创建类型的实例

new T();

当它有很大的力量时,Daeld关键字经常被忽视。我之前写了一篇关于它的博客,讨论了好处(不同的处理),并在产量的引擎盖下发生,以帮助更好地理解。

在C#中使用产量

您可以从扩展方法创建委托,就像它们是常规方法一样,柯里化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<string> aaMaker = "a".Double;Func<string, string> doubler = FunnyExtension.Double;
Console.WriteLine(aaMaker());       //Prints "aa"Console.WriteLine(doubler("b"));    //Prints "bb"

请注意,这对扩展的扩展方法不起作用值类型;参见这个问题

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

[ThreadStatic]private static int _ThreadStaticInteger;

您不应该包含初始化器,因为它在整个应用程序中只执行一次,您最好使该字段为空并在使用它之前检查该值是否为空。

还有一件事ASP.NET应用程序线程是重用的,所以如果你修改了这个值,它最终可能会被用于另一个页面请求。

我仍然发现这在很多情况下很有用。例如,在创建一个自定义事务类时:

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

DbTransaction构造函数将ThreadStatic字段设置为其自身,并在dispose方法中将其重置为null。DoQuery检查静态字段,如果不是,则如果!=null使用当前事务,则默认为其他内容。我们避免了将事务传递给每个方法,此外,它还可以轻松地将原本不打算与事务一起使用的其他方法包装在事务中…

只有一个使用:)

HttpContext.Current.Server.Execute

非常适合将超文本标记语言渲染为AJAX回调的字符串。您可以将其与组件一起使用,而不是拼凑超文本标记语言字符串片段。我能够将页面膨胀减少几百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();

作为不可序列化的营销事件:

[field:NonSerializable]public event SomeDelegate SomeEvent;

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

通常的方式:

handler += new EventHandler(func);

少打字方式:

handler += func;

泛型约束:

 //Constructor constraint, T has a default empty constructorclass Node<K,T> where T : new(){}
//Reference\Value Type constraints//T is a structpublic class MyClass<T> where T : struct
{...}
//T is a reference typepublic class MyClass<T> where T : class
{...}
public class MyClass<T> where T : SomeBaseClass, ISomeInterface
{...}

Or赋值操作符非常好。你可以这样写:

x |= y

而不是这个:

x = x | y

如果您必须以false开头的变量或属性(示例中的x),但您想将其更改为其他布尔变量/属性只有当的值,而其他值为true,这通常是实用的。

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

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

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

String. Join

我见过很多将项目列表转换为带有分隔符的字符串的for循环。确保您不以分隔符开头也不以分隔符结尾总是很痛苦。内置方法使这更容易:

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

待办事项

不是真正的C#功能,更多的是Visual Studio功能。当您以待办事项开始注释时,它会添加到您的Visual Studio任务列表(查看->任务列表。注释)

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

扩展方法满足泛型

您可以将扩展方法与泛型结合起来,当您想到本主题前面的提示时,您可以将扩展添加到特定接口

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

不可数范围

只是想要一个整数列表?

Enumerable.Range(0, 15)

我会试着想出更多…

C#中的指针。

它们可以用来执行就地字符串操作。这是一个不安全的特性,因此不安全关键字用于标记不安全代码的区域。还要注意固定关键字如何用于指示指向的内存被固定并且不能被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);

我永远不会这样做,但只是为了这个问题来演示这个功能。

我喜欢使用使用指令重命名一些类以便于阅读,如下所示:

// defines a descriptive name for a complexed data typeusing MyDomainClassList = System.Collections.Generic.List<MyProjectNameSpace.MyDomainClass>;
....

MyDomainClassList myList = new MyDomainClassList();/* instead ofList<MyDomainClass> myList = new List<MyDomainClass>();*/

这对于代码维护也很方便。如果需要更改类名,则只需要更改一个地方。另一个例子:

using FloatValue  = float; // you only need to change it once to decimal, double...
....FloatValue val1;...

异常过滤。所以“隐藏”你不能甚至在没有编译后补丁的情况下使用它们(至少从C#);)

表达式树怎么样?它们是LINQ的核心,允许失败执行:

取自David Hayden的博客

在C#3.0中,您可以使用lambda表达式定义委托如下:

Func<int,int> f = x => x + 1;

此委托被编译为应用程序中的执行代码,可以这样调用:

var three = f(2); // 2 + 1

代码如您所期望的那样工作。这里没什么特别的。

表达式树

当您使用System. Query. Express将委托定义为表达式树时:

Expression<Func<int,int>> expression = x => x + 1;

委托不再编译为执行代码,而是编译为可以转换和编译为原始委托的数据。

要在应用程序中实际使用表示为表达式树的委托,您必须在应用程序中编译并调用它:

var originalDelegate = expression.Compile();
var three = originalDelegate.Invoke(2);
[field: NonSerialized]public event EventHandler Event;

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

只是[NonSerializ]不起作用,因为NonSerializedAt的属性只能应用于字段。

我特别喜欢可空的DateTime。所以如果你有一些给出日期的情况,而其他没有给出日期的情况,我认为这是最好的使用方式,恕我直言,使用DateTime.MinValue或其他任何东西更容易理解…

DateTime? myDate = null;
if (myDate.HasValue){//doSomething}else{//soSomethingElse}

如果您尝试从项目列表中创建逗号分隔的字符串:

string[] itemList = { "Example 1", "Example 2", "Example 3" };CommaDelimitedStringCollection commaStr = new CommaDelimitedStringCollection();commaStr.AddRange(itemList);//outputs Example 1,Example 2,Example 3

看看这里的另一个例子。

零参数Lambdas

()=>Console.ReadLine()

我没有看到这个:

for (;;);

while (true) ;

我正在成为扩展方法的忠实粉丝,因为它们可以向现有代码或你无法编辑的代码添加非常想要的功能。我现在所做的一切都添加了我最喜欢的一个是字符串。IsNullOr空ty()

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

条件字符串格式

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

string s = string.Format("{0:positive;negative;zero}", i);

e. g.

string format = "000;-#;(0)";
string pos = 1.ToString(format);     // 001string neg = (-1).ToString(format);  // -1string zer = 0.ToString(format);     // (0)

的标准中已经解释了很多。对于任何初学者和专家来说,这都是一本很好的读物,有很多东西要读,但它是官方标准,它充满了多汁的细节。

一旦你完全理解了C#,是时候进一步了解公共语言基础设施的基础知识了。C#的架构和基础。

我遇到过各种各样的程序员,他们不知道对象和ValueType之间的区别,除了它们的附加限制。

熟悉这两个文件,你永远不会成为那个人。

当您需要(a)在对象之间同步通信事件的发生时,有一个名为同步调用的特殊用途接口。

引用MSDN文章(链接):

实现此接口的对象可以接收事件发生的通知,并且可以响应有关该事件的查询。通过这种方式,客户端可以确保在提交取决于第一个请求完成的后续请求之前已经处理了一个请求。

这是一个通用包装器:

protected void OnEvent<T>(EventHandler<T> eventHandler, T args) where T : EventArgs{if (eventHandler == null) return;
foreach (EventHandler<T> singleEvent in eventHandler.GetInvocationList()){if (singleEvent.Target != null && singleEvent.Target is ISynchronizeInvoke){var target = (ISynchronizeInvoke)singleEvent.Target;
if (target.InvokeRequired) {target.BeginInvoke(singleEvent, new object[] { this, args });continue;}}singleEvent(this, args);}}

下面是一个示例用法:

public event EventHandler<ProgressEventArgs> ProgressChanged;
private void OnProgressChanged(int processed, int total){OnEvent(ProgressChanged, new ProgressEventArgs(processed, total));}

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

new Dictionary<string, Int64>() \{\{"Testing", 123}, {"Test", 125}};

我不认为有人提到在值类型名称之后附加?会使其为空。

你可以这样做:

DateTime? date = null;

DateTime是一个结构。

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

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

泛型和奇怪地重复出现的模板模式确实有助于一些静态方法/属性声明。

假设您正在构建一个类层次结构:

class Base{}
class Foo: Base{}
class Bar: Base{}

现在,您想在您的类型上声明静态方法,这些方法应该采用相同类型的参数(或返回值)或相同类型的静态属性。例如,您想要:

class Base{public static Base Get(){// Return a suitable Base.}}
class Foo: Base{public static Foo Get(){// Return a suitable Foo.}}
class Bar: Base{public static Bar Get(){// Return a suitable Bar.}}

如果这些静态方法基本上都做同样的事情,那么你手上有很多重复的代码。一种解决方案是在返回值上删除类型安全并始终返回类型Base。然而,如果你想要类型安全,那么解决方案是将Base声明为:

class Base<T> where T: Base<T>{public static T Get<T>(){// Return a suitable T.}}

你的FooBar是:

class Foo: Base<Foo>{}
class Bar: Base<Bar>{}

这样,他们将自动获得他们的副本静态方法。

这也可以奇迹般地将Singleton模式封装在基类中(我知道下面的代码不是线程安全的,只是为了演示一点):

public class Singleton<T> where T: Singleton<T>, new(){public static T Instance { get; private set; }
static Singleton<T>(){Instance = new T();}}

我意识到这迫使你在你的单例子类上有一个公共的无参数构造函数,但是在没有where T: protected new()构造的情况下,没有办法在编译时避免这种情况;然而,可以使用反射在运行时调用子类的受保护/私有无参数构造函数来实现这一点。

阻止DataGridView显示属性:

[System.ComponentModel.Browsable(false)]public String LastActionID{get; private set;}

允许您为组件设置友好的显示(如DataGrid或DataGridView):

[System.ComponentModel.DisplayName("Last Action")]public String LastAction{get; private set;}

对于你的后备变量,如果你不希望任何东西直接访问它们,这会使它变得更加困难:

[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]private DataController p_dataSources;

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

我最近学到的一个是你仍然可以调用可空值上的方法……

事实证明,当你有一个可空值时:

decimal? MyValue = null;

你可能认为你必须写:

MyValue == null ? null : MyValue .ToString()

你可以这样写:

MyValue.ToString()

我知道我可以调用MyValue. HasValue和MyValue. Value……但它并没有完全点击我可以调用ToString()。

这不会编译:

namespace ns{class Class1{Nullable<int> a;}}

找不到类型或命名空间名称“Nullable”(您是否缺少使用指令或程序集引用?)<--缺少'using System;'

但是

namespace ns{class Class1{int? a;}}

将编译!(. NET 2.0)。

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

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

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

类似JavaScript的匿名内联函数

返回一个字符串:

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

返回一个更复杂的对象:

var d = new Func<Dictionary<Int32, String>>(() =>{return new Dictionary<Int32, String>\{\{ 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<String>(() =>{return @"Result of a chunk of logic, without having to definethe logic outside of the TableCell constructor";})()},
new TableCell { Text = "" },new TableCell { Text = "" }});

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


替代语法

// The one-linerFunc<Int32, Int32, String> Add = (a, b) => Convert.ToString(a + b);
// Multiple linesFunc<Int32, Int32, String> Add = (a, b) =>{var i = a + b;
return i.ToString();};
// Without parametersFunc<String> Foo = () => "";
// Without parameters, multiple linesFunc<String> Foo = () =>{return "";};

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

Func<String, String> Shorten = s => s.Length > 100 ? s.Substring(0, 100) + "&hellip;" : s;

首先-代理类型

[DebuggerTypeProxy(typeof(HashtableDebugView))]class MyHashtable : Hashtable{private const string TestString ="This should not appear in the debug window.";
internal class HashtableDebugView{private Hashtable hashtable;public const string TestStringProxy ="This should appear in the debug window.";
// The constructor for the type proxy class must have a// constructor that takes the target type as a parameter.public HashtableDebugView(Hashtable hashtable){this.hashtable = hashtable;}}}

第二点:

ICustomTypeDetptor

如果有人提到这个,我很抱歉,但我经常使用这个。

Alex Papadimoulis开发了Visual Studio的加载项。它用于将常规文本粘贴为字符串、字符串生成器、注释或区域。

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 textAnother with a ""quote""!!";

定义自定义属性时,您可以将它们与[MyAtAt的属性]或[MyAtt]一起使用。当两种写作都存在类时,会发生编译错误。

@特殊字符可用于区分它们:

[AttributeUsage(AttributeTargets.All)]public class X: Attribute{}
[AttributeUsage(AttributeTargets.All)]public class XAttribute: Attribute{}
[X]      // Error: ambiguityclass Class1 {}
[XAttribute]   // Refers to XAttributeclass Class2 {}
[@X]      // Refers to Xclass Class3 {}
[@XAttribute]   // Refers to XAttributeclass Class4 {}

您可以在一个use语句中“使用”多个对象。

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

这和我的不一样。

不确定微软是否会喜欢这个问题,尤其是有这么多回复。我相信我曾经听过一位微软负责人说:

隐藏的功能是浪费的功能

…或者类似的东西。

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

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

test2只存在于括号中。

抱歉这么晚发帖,我是Stack Overflow的新手,所以错过了早期的机会。

我发现EventHandler<T>是未充分利用的框架的一个很好的特性。

我遇到的大多数C#开发人员在定义自定义事件时仍然定义自定义事件处理程序委托,这不再是必要的。

而不是:

public delegate void MyCustomEventHandler(object sender, MyCustomEventArgs e);
public class MyCustomEventClass{public event MyCustomEventHandler MyCustomEvent;}

你可以去:

public class MyCustomEventClass{public event EventHandler<MyCustomEventArgs> MyCustomEvent;}

这要简洁得多,而且您不会陷入是将委托放在包含事件的类的. cs文件中,还是将EventArgs派生类放入. cs文件中的困境。

开放泛型是另一个方便的功能,特别是在使用控制权倒置时:

container.RegisterType(typeof(IRepository<>), typeof(NHibernateRepository<>));

在包含转义字符的字符串之前使用@。基本上,当使用物理路径在字符串变量中赋值时,每个人都使用“\”,其中转义字符存在于字符串中。

例如string strPath="D:\网站\web1\图像\";

但是可以在字符串值之前使用@忽略转义字符。

例如string strPath=@"D:\网站\web1\图像\";

我喜欢滥用静态模板类不共享其静态成员的事实。

这是一个线程安全(在创建时)和廉价的替代任何Dictionary<Type,...>Type实例在编译时已知。

public static class MyCachedData<T>{static readonly CachedData Value;static MyCachedData(){Value=// Heavy computation, such as baking IL code or doing lots of reflection on a type}}

干杯。弗洛里安

下面的代码并没有隐藏,但是很隐含。我不知道是否有类似下面这样的示例发布在这里,也看不出有什么好处(可能什么好处都没有),但我会尝试展示一段“奇怪”的代码。下面的示例通过C#中的函子(委托/匿名委托[lambdas])和闭包模拟了for语句。其他流语句如ifif/elsewhiledo/whle也被模拟,但我不确定switch(也许,我太懒了:))。我稍微压缩了示例源代码以使其更清楚。

private static readonly Action EmptyAction = () => { };private static readonly Func<bool> EmptyCondition = () => { return true; };
private sealed class BreakStatementException : Exception { }private sealed class ContinueStatementException : Exception { }private static void Break() { throw new BreakStatementException(); }private static void Continue() { throw new ContinueStatementException(); }
private static void For(Action init, Func<bool> condition, Action postBlock, Action statement) {init = init ?? EmptyAction;condition = condition ?? EmptyCondition;postBlock = postBlock ?? EmptyAction;statement = statement ?? EmptyAction;for ( init(); condition(); postBlock() ) {try {statement();} catch ( BreakStatementException ) {break;} catch ( ContinueStatementException ) {continue;}}}
private static void Main() {int i = 0; // avoiding error "Use of unassigned local variable 'i'" if not using `for` init blockFor(() => i = 0, () => i < 10, () => i++,() => {if ( i == 5 )Continue();Console.WriteLine(i);});}

如果我没有错的话,这种方法与函数式编程实践非常相关。我对吗?

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

public interface IReadOnlyFoo{object SomeReadOnlyProperty { get; }}

具体类是这样的:

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

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

// Create a Foo instanceFoo foo = new Foo();
// This statement is legalfoo.SomeReadOnlyProperty = 12345;
// Make Foo read onlyIReadOnlyFoo readOnlyFoo = foo;
// This statement won't compilereadOnlyFoo.SomeReadOnlyProperty = 54321;

我只是想在没有注释的情况下复制该代码。所以,诀窍是只需按下Alt按钮,然后突出显示您喜欢的矩形。(例如。g.下面)。

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键并选择矩形,无需取消注释行。

看看这个。

C#+CLR:

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

  2. volatile, Thread.VolatileRead, Thread.VolatileWrite:很少有人使用这些,更少的人了解他们避免和引入的所有风险:)。

  3. ThreadStatic变量:在过去的几年里,只有一种情况,我发现ThreadStatic变量绝对是上帝的恩赐和不可或缺的。例如,当你想为整个调用链做某事时,它们非常有用。

  4. fixed关键字:当你想访问大数组的元素几乎和C++一样快时,它是一个隐藏的武器(默认情况下,C#强制执行绑定检查以减慢速度)。

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

  6. 我使用的一个方便的特性是DataRow[columnName].ToString()总是返回非空值。如果数据库中的值为NULL,则会得到空字符串。

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

#if DEBUGif (Debugger.IsAttached)Debugger.Break();#endif
  1. 您可以为复杂难看的泛型类型添加别名,这样您就不必一次又一次地复制粘贴它们。您还可以在一个地方对该类型进行更改。例如,
using ComplicatedDictionary = Dictionary<int, Dictionary<string, object>>;ComplicatedDictionary myDictionary = new ComplicatedDictionary();

需要返回一个空的IENumable吗?

public IEnumerable<T> GetEnumerator(){yield break;}

工厂方法的类型推断

我不知道这是否已经发布(我扫描了第一个帖子,找不到它)。

这最好用一个例子来展示,假设你有这个类(模拟一个元组),为了演示所有使这成为可能的语言特性,我将一步一步地介绍它。

public class Tuple<V1, V2> : Tuple{public readonly V1 v1;public readonly V2 v2;
public Tuple(V1 v1, V2 v2){this.v1 = v1;this.v2 = v2;}}

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

Tuple<int, string> tup = new Tuple<int, string>(1, "Hello, World!");

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

var tup = new Tuple<int, string>(1, "Hello, World!");

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

public static void Create<T1, T2>(){// stuff}

调用它是,再一次常识,这样做:

Create<float, double>();

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

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

这两个调用是相同的:

Create<float, string>(1.0f, "test");Create(1.0f, "test");

由于T1和T2是从你传递的参数中推断出来的。将这些知识与var关键字结合起来,我们可以通过添加第二个带有静态方法的静态类,例如:

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

达到这个效果:

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

这意味着:变量“tup”的类型、“创建”的类型参数和“创建”的返回值都是从您作为参数传递给创建的类型推断出来的

完整的代码看起来像这样:

public abstract class Tuple{public static Tuple<V1, V2> Create<V1, V2>(V1 v1, V2 v2){return new Tuple<V1, V2>(v1, v2);}}
public class Tuple<V1, V2> : 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");

这给了你完全类型推断工厂方法无处不在!

我喜欢编辑器眉毛可属性。它允许您控制是否在智能感知中显示方法/属性。您可以将值设置为始终、高级或从不。

从msdn

备注

EditorBrowablleAt的是对设计器的提示,指示是否显示属性或方法。您可以在可视化设计器或文本编辑器中使用此类型来确定用户可见的内容。例如,Visual Studio中的IntelliSense引擎使用此属性来确定是否显示属性或方法。

在Visual C#中,您可以控制高级属性何时出现在IntelliSense和属性窗口中,并在工具|选项|文本编辑器|C#下设置隐藏高级成员。

轻松确定变量类型为宣布(来自我的答案):

using System;using System.Collections.Generic;
static class Program{public static Type GetDeclaredType<T>(T x){return typeof(T);}
// Demonstrate how GetDeclaredType worksstatic void Main(string[] args){IList<string> iList = new List<string>();List<string> list = null;
Console.WriteLine(GetDeclaredType(iList).Name);Console.WriteLine(GetDeclaredType(list).Name);}}

结果:

IList`1List`1

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

static void Main(string[] args){Console.WriteLine("Name is '{0}'", GetName(new {args}));Console.ReadLine();}
static string GetName<T>(T item) where T : class{var properties = typeof(T).GetProperties();return properties[0].Name;}

结果:Name is 'args'

将枚举值转换为字符串值

给定枚举

enum Country{UnitedKingdom,UnitedStates,UnitedArabEmirates,}

使用它:

public static void PrintEnumAsString( Country country ){Console.Writeline( country.ToString() );}

将以字符串形式打印枚举值的名称,例如“UnitedUK”

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

如果您需要一个与通过某个接口的值类型变量(由此值类型实现)一起工作的方法,则在方法调用期间很容易避免拳击

示例代码:

using System;using System.Collections;
interface IFoo {void Foo();}struct MyStructure : IFoo {public void Foo() {}}public static class Program {static void MethodDoesNotBoxArguments<T>(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  8IL_0000:  ldarga.s   tIL_0002:  constrained. !!TIL_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   sIL_0002:  initobj    MyStructureIL_0008:  ldloc.0IL_0009:  call       void Program::MethodDoesNotBoxArguments<valuetype MyStructure>(!!0)IL_000e:  ret} // end of method Program::Main

参见Richter, J. CLR via C#,第2版,第14章:接口,关于泛型和接口约束的部分。

另见另一个问题我的答案

我能想到的一对夫妇:

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

这会防止事件被序列化。“field:”表示该属性应应用于事件的支持字段。

另一个鲜为人知的功能是覆盖添加/删除事件处理程序:

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

__arglist也是

[DllImport("msvcrt40.dll")]public static extern int printf(string format, __arglist);
static void Main(string[] args){printf("Hello %s!\n", __arglist("Bart"));}

字典初始化程序对于需要硬编码某些数据的快速破解和单元测试总是有用的。

var dict = new Dictionary<int, string> { { 10, "Hello" }, { 20, "World" } };

Action和Func委托帮助程序与lambda方法结合使用。我将这些用于需要委托以提高易读性的简单模式。例如,一个简单的缓存模式是检查请求的对象是否存在于缓存中。如果它确实存在:返回缓存的对象。如果它不存在,生成一个新实例,缓存新实例并返回新实例。相反,为我可能从缓存中存储/检索的每个对象编写此代码1000次,我可以编写一个简单的模式方法,就像这样…

private static T CachePattern<T>(string key, Func<T> create) where T : class{if (cache[key] == null){cache.Add(key, create());}
return cache[key] as T;}

…然后我可以通过在我的自定义缓存管理器中使用以下内容来大大简化我的缓存获取/设置代码

public static IUser CurrentUser{get{return CachePattern<IUser>("CurrentUserKey", () => repository.NewUpUser());}}

现在简单的“日常”代码模式可以编写一次并更容易重用,IMHO。我不必去编写委托类型并弄清楚我想如何实现回调等。如果我能在10秒内编写它,我就不那么倾向于求助于剪切/粘贴简单的代码模式,无论它们是懒惰初始化还是上面显示的其他一些例子…

"待办事项"属性和任务列表

//TODO: [something]

将其添加到代码中(行间距很重要)会在任务列表中抛出一个项目,双击该项目将跳转到代码中的适当位置。

我不知道可以帮助避免使用方法重载的泛型方法。下面是重载的方法来打印整数和双倍数。

    private static void printNumbers(int [] intNumbers){foreach(int element in intNumbers){Console.WriteLine(element);}
}
private static void printNumbers(double[] doubleNumbers){foreach (double element in doubleNumbers){Console.WriteLine(element);}}

通用方法,有助于为上述两种方法提供一种方法

    private static void printNumbers<E>(E [] Numbers){foreach (E element in Numbers){Console.WriteLine(element);}}
  • ?附加到类型以使其成为可以为空,例如:int?
  • "c:\dir"而不是@"C:\dir"C:\dir

使用LINQ更容易上眼/浓缩ORM映射

看看这个表:

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

这个结构:

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



而不是像这样做:

List<Message> messages = new List<Message>();
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();

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

读完这9页后,我觉得我必须指出一个不为人知的特性……

这适用于. NET 1.1,在gzip文件上使用压缩/解压,必须:

  • 下载ICSharpCode. ZipLib
  • 或者,将Java库引用到您的项目中,并使用Java的内置库来利用GZip的压缩/解压缩方法。

它未被充分利用,我不知道,(仍然使用ICSharpCode. ZipLib,即使使用. NET 2/3.5)是它被合并到标准BCL版本2中,在System.IO.Compress命名空间中……请参阅MSDN页面“GZipStream类”。

我发现在Visual Studio中使用条件中断函数非常有用。我喜欢它允许我将值设置为某些值的方式,例如只能在极少数情况下遇到,并且从那里我可以进一步检查代码。

不知道这本身是否是一个秘密,但我喜欢System. Linq中添加的E的(添加到IE的)类。

http://msdn.microsoft.com/en-us/library/system.linq.enumerable_members.aspx

迭代器块太神奇了。我用它们来构建列表,这些列表将被测试以查看它们是否是共质数。它基本上允许您查看一个逐个返回值的函数并随时停止。

哦,我差点忘了世界上最好的类,当你不能再优化它的时候。背景工作者!!!!

http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.aspx

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

另一种方式,通过不明确地创建一个IENumable对象而产生的产量

public IEnumerable<Request> SomeMethod(IEnumerable<Request> requests){foreach (Request request in requests)yield return DoSomthing(request);}

我只是想提一下(因为OP表示T: struct)C#编译器的一个陷阱是

where T : Enum

不会编译。它抛出错误“Constraint不能是特殊类'System. Enum'”。

对象初始化器中的集合初始化器:

MailMessage mail = new MailMessage {To = { new MailAddress("a@example.com"), new MailAddress("b@example.com") },Subject = "Password Recovery"};

您可以在单个表达式中初始化整个树。

我在这次谈话中有点晚了,我想贡献以下内容。对于一些开发人员来说,这可能是一件新事物。

public class User{public long UserId { get; set; }public String Name { get; set; }public String Password { get; set; }public String Email { get; set; }}

声明和初始化它的通常方法是使用构造函数或类似的方法。

User user = new User();user.UserId = 1;user.Name = "myname";etc

我知道Visual Basic开发人员会喜欢它,因为它就像只有在VB.NET中可用的运算符,而在C#中不可用,如下所示。

User user = new User(){UserId = 1,Name = "myname",Email = "myemail@domain.com",Password = "mypassword"};

您可以在Enum中存储颜色。

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

这个调用私有方法的技巧非常整洁。

var subject = new Subject();var doSomething = (Func<String, String>)Delegate.CreateDelegate(typeof(Func<String, String>), subject, "DoSomething");Console.WriteLine(doSomething("Hello Freggles"));

这是一个有用的上下文

我不知道这是否是一个隐藏的功能 (""). 任何字符串函数。

若要使用LINQ测试IENumable<T>是否为空,请使用:

<T>.任何();

  • 一开始,我用的是(iemenable<T>. Count() ! = 0)…
    • 这会不必要地导致枚举IENumable<T>中的所有项。
  • 作为对此的改进,我继续使用(IENumable<T>. FirstOrDefault()==null)…
    • 哪个更好…
  • 但是IENumable<T>. any()是最简洁的,并且性能最好。

大多数P/调用的东西有点奇怪。

属性示例:

[DllImport ("gdi32.dll")][return : MarshalAs(UnmanagedType.I4)][StructLayout(LayoutKind.Sequential)]

允许带大括号的空块。

你可以这样写代码

{service.DoTonsOfWork(args);}

当你想尝试一些没有你已经写过的usingtry... finally的东西时,这很有帮助。

//using(var scope = new TransactionScope){service.DoTonsOfWork(args);}

Visual Studio最有用的功能之一是“制作对象id”。它生成一个id并“附加”到对象,因此无论您在哪里查看对象,您都将看到该id(无论线程如何)。

在调试时右键单击变量工具提示,您就拥有了它。它也适用于监视/汽车/本地变量。

使用"~"运算符与FlagAt的和枚举
有时我们会使用带有枚举的Fags属性来对枚举执行按位操作。

 [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.}

使用LINQ,可以根据参数创建新函数。如果你有一个经常执行的小函数,那就太好了,但是参数需要一些时间来计算。

    public Func<int> RandomGenerator{get{var r = new Random();return () => { return r.Next(); };}}
void SomeFunction(){var result1 = RandomGenerator();
var x = RandomGenerator;var result2 = x();}

任意嵌套范围{}


1.更精细的范围界定行为

{在成员}{中的任何位置,仅使用大括号}{,没有控制语句}

void MyWritingMethod() {
int sameAge = 35;

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

{ // scope some other workstring 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(..);
//<root>xw.WriteStartElement("root");{//<game>xw.WriteStartElement("game");{//<score>#</score>for (int i = 0; i < scores.Length; ++i) // multiple scoresxw.WriteElementString("score", scores[i].ToString());
}//</game>xw.WriteEndElement();}//</root>xw.WriteEndElement();

3.模仿“with”语句

(也是将临时工作排除在主范围之外的另一种用途)
帕特里克提供:有时用于模仿C#中的VB“with语句”。

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

对于挑剔的程序员。

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

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

这与静态构造函数有关。这是一种执行静态销毁(即在程序退出时清理资源)的方法。

第一堂课:

class StaticDestructor{/// <summary>/// The delegate that is invoked when the destructor is called./// </summary>public delegate void Handler();private Handler doDestroy;
/// <summary>/// Creates a new static destructor with the specified delegate to handle the destruction./// </summary>/// <param name="method">The delegate that will handle destruction.</param>public StaticDestructor(Handler method){doDestroy = method;}
~StaticDestructor(){doDestroy();}}

然后作为类的成员,您希望有一个“静态析构函数”:

private static readonly StaticDestructor destructor = new StaticDestructor(delegate(){//Cleanup here});

这将在最终垃圾回收机制发生时调用。如果您绝对需要释放某些资源,这很有用。

一个表现出这种行为的快速而肮脏的程序:

using System;
namespace TestStaticDestructor{class StaticDestructor{public delegate void Handler();private Handler doDestroy;
public StaticDestructor(Handler method){doDestroy = method;}
~StaticDestructor(){doDestroy();}}
class SomeClass{static SomeClass(){Console.WriteLine("Statically constructed!");}
static readonly StaticDestructor destructor = new StaticDestructor(delegate(){Console.WriteLine("Statically destructed!");});}
class Program{static void Main(string[] args){SomeClass someClass = new SomeClass();someClass = null;System.Threading.Thread.Sleep(1000);}}}

当程序退出时,调用“静态析构函数”。

默认值为空。

我喜欢

#if DEBUG//Code run in debugging mode
#else//Code run in release mode
#endif

参考后w/perma链接“C#的隐藏特性?”,还有另一种方法可以完成相同的缩进/换行符。看看这个…

XmlWriterSettings xmlWriterSettings = new XmlWriterSettings();xmlWriterSettings.NewLineOnAttributes = true;xmlWriterSettings.Indent = true;

XmlWriter xml = XmlWriter.Create(@"C:\file.xml", xmlWriterSettings);
// Start writing the data using xml.WriteStartElement(), xml.WriteElementString(...), xml.WriteEndElement() etc

我不确定这是否是一个未知的功能!

IObservable怎么样?

几乎每个人都知道I无数,但他们的数学对偶似乎是未知的我可观察。也许是因为它是新的。NET 4。

它所做的不是拉取信息(如枚举),而是将信息推送到可观察对象的订阅者。

Rx扩展一起,它将改变我们处理事件的方式。只是为了说明它有多强大,请查看一个非常简短的示例<强>这里

当一个类实现我通知物业变更并且您想通知绑定系统(WPF、Silverlight等)对象(ViewModel)的多个绑定属性已更改时,您可以使用null字符串空引发属性更改事件。

这在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);}}}

这意味着T必须有一个公共的无参数构造函数:

 class MyClass<T> where T : new(){
}

我正在阅读“ProASP.NETMVC Framework”(APress)一书,并观察到作者正在使用一个对我来说陌生的字典对象。

他在不使用Add()方法的情况下添加了一个新的键/值对。然后他覆盖了同一个键/值对,而无需检查该键是否已经存在。例如:

Dictionary<string, int> nameAgeDict = new Dictionary<string, int>();nameAgeDict["Joe"] = 34;      // no error. will just auto-add key/valuenameAgeDict["Joe"] = 41;      // no error. key/value just get overwrittennameAgeDict.Add("Joe", 30);   // ERROR! key already exists

在很多情况下,我不需要检查我的字典是否已经有一个键,我只想添加相应的键/值对(如有必要,覆盖现有的键/值对)。

根据周围类的泛型类型分隔静态字段。

    public class StaticConstrucEx2Outer<T> {
// Will hold a different value depending on the specicified generic typepublic T SomeProperty { get; set; }
static StaticConstrucEx2Outer() {Console.WriteLine("StaticConstrucEx2Outer " + typeof(T).Name);}
public class StaticConstrucEx2Inner<U, V> {
static StaticConstrucEx2Inner() {
Console.WriteLine("Outer <{0}> : Inner <{1}><{2}>",typeof(T).Name,typeof(U).Name,typeof(V).Name);}
public static void FooBar() {}}
public class SCInner {
static SCInner() {Console.WriteLine("SCInner init <{0}>", typeof(T).Name);}
public static void FooBar() {}}}

StaticConstrucEx2Outer<int>.StaticConstrucEx2Inner<string, DateTime>.FooBar();StaticConstrucEx2Outer<int>.SCInner.FooBar();
StaticConstrucEx2Outer<string>.StaticConstrucEx2Inner<string, DateTime>.FooBar();StaticConstrucEx2Outer<string>.SCInner.FooBar();
StaticConstrucEx2Outer<string>.StaticConstrucEx2Inner<string, Int16>.FooBar();StaticConstrucEx2Outer<string>.SCInner.FooBar();
StaticConstrucEx2Outer<string>.StaticConstrucEx2Inner<string, UInt32>.FooBar();
StaticConstrucEx2Outer<long>.StaticConstrucEx2Inner<string, UInt32>.FooBar();

将产生以下输出

Outer <Int32> : Inner <String><DateTime>SCInner init <Int32>
Outer <String> : Inner <String><DateTime>SCInner init <String>
Outer <String> : Inner <String><Int16>
Outer <String> : Inner <String><UInt32>
Outer <Int64> : Inner <String><UInt32>

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

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

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

当你可以写:

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

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

宽度string.Format()

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

产生

alt文本

普拉比尔的博客|隐藏的C#功能

最近我学习了String. Join方法。当构建类似列的字符串以供查询选择时,它非常有用。

typedef

有人发帖说他们想念typedef,但你可以这样做

using ListOfDictionary = System.Collections.Generic.List<System.Collections.Generic.Dictionary<string, string>>;

并宣布其为

ListOfDictionary list = new ListOfDictionary();

这是C#4.0中string类的新方法:

String.IsNullOrWhiteSpace(String value)

是时候了。

不是真的隐藏,但很有用。当你有一个enumflags的时候,你可以使用Shift-left来使事情变得更清楚。

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

关于事件处理程序的另一个注意事项:您可以简单地创建一个提升扩展方法,如下所示:

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

然后你可以使用它来引发事件:

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

此方法具有强制执行编码标准(使用EventHandler<>)的额外优势。

一遍又一遍地编写相同的函数是没有意义的。也许C#的下一个版本最终会有一个InlineAttribute可以放在扩展方法上,并将导致编译器内联方法定义(这将使这种方式几乎成为标准,也是最快的)。

编辑:基于注释的扩展方法中删除了临时变量

调试时,您可以在Watch\QuickWatch\立即窗口中键入$exception并获取有关当前帧异常的所有信息。如果您打开了第一次机会异常,这将非常有用!

我不宽恕它,但我很惊讶goto仍然在导弹来袭左右

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

这是超级先进的,我还没有看到其他人使用它-这可能意味着它对大多数人来说也没有那么有用-但它是值得了解的事情之一。

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

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

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

IDAL<T> GetDAL<T>(); // 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<DALToBeProfiled>.Instance(dal);
// Now use proxy wherever we would have used the original...// All methods' timings are automatically recorded// with a high-resolution timerDoStuffToThisObject(dalProxy);
// Output profiling resultsProfileManager.Instance.ToConsole();}

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

[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)][SecurityPermission(SecurityAction.LinkDemand,Flags = SecurityPermissionFlag.Infrastructure)] // per FxCoppublic 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 valuestring profileName = ProfileClassName + "." + mi.Name;
using (ProfileManager.Start(profileName)){IMessage myReturnMessage =RemotingServices.ExecuteMessage(_target, msgMethodCall);
retval = myReturnMessage;}
return retval;}

. NET能做什么是不是很有趣?唯一的限制是目标类型必须是从按引用对象封送派生的。我希望这对某人有帮助。

也有用,但不常用:限制执行区域

引用BCL Team博客:

约束执行区域(CER)来帮助一个开发者写她保持一致性的代码。CLR并不能保证开发商的代码是正确的,但CLR确实如此提升所有运行时诱导的故障点(即异步异常)在代码运行之前,或完成后。结合限制开发者可以做什么放入CER,这些是有用的方法做出强有力的保证您的代码是否会执行。CER的都准备好了,这意味着当我们看到一个,我们会急切地JIT在其静态可发现调用图。如果CLR的主机关心堆栈溢出,我们将探测一些数量堆栈空间(尽管可能没有足够的堆栈空间任意方法*)。我们也延迟线程中止,直到CER运行完毕

当以原子方式对数据结构的多个字段进行编辑时,它很有用。因此,对对象进行事务处理很有帮助。

关键完成r对象似乎也被隐藏了(至少没有编写不安全代码的人)。CriticalFinalizerObject保证垃圾回收机制将执行终结器。在分配时,终结器及其调用图已提前准备好。

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

此事件提供未捕获异常的通知。它允许应用程序在系统默认处理程序向用户报告异常并终止应用程序之前记录有关异常的信息。如果有足够的有关应用程序状态的信息,可能会执行其他操作,例如保存程序数据以供以后恢复。建议注意,因为不处理异常时程序数据可能会损坏。

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

string.Empty

我知道这不是幻想(可笑的奇怪),但我一直在使用它而不是“”。

它隐藏得很好,直到有人告诉你它在那里。

固定语句

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

固定语句设置一个指向托管变量的指针,并在语句执行期间“固定”该变量。

stackalloc

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

您可以将多个属性放在一对方括号中:

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

不确定这篇文章是否被提及(11页!!)

但是,当您对将要序列化的类/对象进行版本控制时,类的OptionalField属性是惊人的。

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

从匿名方法访问局部变量允许您使用新的控制流逻辑包装几乎任何代码,而无需将该代码分解为另一个方法。在方法外部声明的局部变量在方法内部可用,例如此处示例中的endOfLineChar局部变量:

http://aaronls.wordpress.com/2010/02/02/retrying-on-exception-conditionally/

您可以组合protectedinternal访问器以使其在同一程序集中公开,但在不同的程序集中受到保护。这可以用于字段、属性、方法甚至常量。