值得 .NET 开发者了解的15个特性
本文翻译自:https://www.codeproject.com/Articles/1021335/Top-Underutilized-Features-of-NET
转载请注明出自:葡萄城官网,葡萄城为开发者提供专业的开发工具、解决方案和服务,赋能开发者。
本文列举了 15 个值得了解的 C# 特性,旨在让 .NET 开发人员更好的使用 C# 语言进行开发工作。
1. ObsoleteAttributeObsoleteAttribute 适用于除组件、模块、参数和返回值以外的所有程序元素。将元素标记为 obsolete,可以通知用户该元素将在未来的版本中删除。
IsError- 设置为 true,编译器将在代码中使用这个属性时,提示错误。
publicstaticclassObsoleteExample{//MarkOrderDetailTotalAsObsolete.[ObsoleteAttribute("Thisproperty(DepricatedOrderDetailTotal)isobsolete.UseInvoiceTotalinstead.",false)]publicstaticdecimalOrderDetailTotal{get{return12m;}}publicstaticdecimalInvoiceTotal{get{return25m;}}//MarkCalculateOrderDetailTotalAsObsolete.[ObsoleteAttribute("Thismethodisobsolete.CallCalculateInvoiceTotalinstead.",true)]publicstaticdecimalCalculateOrderDetailTotal(){return0m;}publicstaticdecimalCalculateInvoiceTotal(){return1m;}}
如果我们在代码中使用上述类,则会显示错误和警告。
Console.WriteLine(ObsoleteExample.OrderDetailTotal);Console.WriteLine();Console.WriteLine(ObsoleteExample.CalculateOrderDetailTotal());
官方文档-https://msdn.microsoft.com/en-us/library/system.obsoleteattribute.aspx
2. 使用 DefaultValueAttribute 为 C# 自动实现的属性设置默认值DefaultValueAttribute 可以指定属性的默认值。你可以使用 DefaultValueAttribute 创建任意一个值。成员的默认值通常是其初始值。
这个属性不能用于使用特定的值自动初始化对象成员。因此,开发者必须在代码中设置初始值。
publicclassDefaultValueAttributeTest{publicDefaultValueAttributeTest(){//UsetheDefaultValuepropertyofeachpropertytoactuallysetit,viareflection.foreach(PropertyDescriptorpropinTypeDescriptor.GetProperties(this)){DefaultValueAttributeattr=(DefaultValueAttribute)prop.Attributes[typeof(DefaultValueAttribute)];if(attr!=null){prop.SetValue(this,attr.Value);}}}[DefaultValue(25)]publicintAge{get;set;}[DefaultValue("Anton")]publicstringFirstName{get;set;}[DefaultValue("Angelov")]publicstringLastName{get;set;}publicoverridestringToString(){returnstring.Format("{0}{1}is{2}.",this.FirstName,this.LastName,this.Age);}}
自动实现的属性通过反射在类的构造函数中实现初始化。代码遍历类的所有属性,并将它们设置为默认值。
官方文档-https://msdn.microsoft.com/zh-CN/library/system.componentmodel.defaultvalueattribute.aspx
3. DebuggerBrowsableAttributeDebuggerBrowsableAttribute 用于确定是否需要以及如何实现在调试器变量窗口中显示成员变量。
publicstaticclassDebuggerBrowsableTest{privatestaticstringsquirrelFirstNameName;privatestaticstringsquirrelLastNameName;//ThefollowingDebuggerBrowsableAttributepreventsthepropertyfollowingit//fromappearinginthedebugwindowfortheclass.[DebuggerBrowsable(DebuggerBrowsableState.Never)]publicstaticstringSquirrelFirstNameName{get{returnsquirrelFirstNameName;}set{squirrelFirstNameName=value;}}[DebuggerBrowsable(DebuggerBrowsableState.Collapsed)]publicstaticstringSquirrelLastNameName{get{returnsquirrelLastNameName;}set{squirrelLastNameName=value;}}}
官方文档-https://msdn.microsoft.com/zh-CN/library/system.diagnostics.debuggerbrowsableattribute.aspx
4. ??运算符当左操作数非空时,??运算符返回左边的操作数,否则返回右边的操作数。??运算符定义为,将可空类型分配给非空类型时要返回的默认值。
int?x=null;inty=x??-1;Console.WriteLine("ynowequals-1becausexwasnull=>{0}",y);inti=DefaultValueOperatorTest.GetNullableInt()??default(int);Console.WriteLine("iequalsnow0becauseGetNullableInt()returnednull=>{0}",i);strings=DefaultValueOperatorTest.GetStringValue();Console.WriteLine("Returns'Unspecified'becausesisnull=>{0}",s??"Unspecified");
官方文档-https://msdn.microsoft.com/zh-cn/library/ms173224(v=vs.80).aspx
5. Curry和 Partial 方法Curry- 在数学和计算机科学中,currying 是一种将函数的评估转换为多个参数(或参数元组)的技术,主要用于评估一系列函数,每个函数都有一个参数。
为了通过 C# 实现,使用扩展方法的功能。
Func<A,Func<B,Func<C,R>>>Curry<A,B,C,R>(Func<A,B,C,R>a=>b=>c=><,,,>addNumbers=(x,y,z)=>x+y+f1=<,Func<,>>f2=f1(<,>f3=f2());
不同方法返回的类型可以与var关键字进行交换。
官方文档-https://en.wikipedia.org/wiki/Currying#/Contrast_with_partial_function_application
Partial- 在计算机科学中,Partial应用程序(或 Partial功能应用程序)是指将一些参数固定到一个函数的过程,从而产生另一个更小的函数。
publicstaticclassCurryMethodExtensions{publicstaticFunc<C,R>Partial<A,B,C,R>(thisFunc<A,B,C,R>f,Aa,Bb){returnc=>f(a,b,c);}}
Partial扩展方法的使用比 Curry更直接。
Func<int,int,int,int>sumNumbers=(x,y,z)=>x+y+z;Func<int,int>f4=sumNumbers.Partial(3,4);Console.WriteLine(f4(5));
官方文档-https://en.wikipedia.org/wiki/Partial_application
6. WeakReference弱引用使得在收集器收集对象时,仍允许应用程序访问该对象。如果你需要这个对象,你仍然可以获得一个强有力的引用,并阻止它被收集。
WeakReferenceTesthugeObject=newWeakReferenceTest();hugeObject.SharkFirstName="Sharky";WeakReferencew=newWeakReference(hugeObject);hugeObject=null;GC.Collect();Console.WriteLine((w.TargetasWeakReferenceTest).SharkFirstName);
如果垃圾收集器没有明确被地调用,那么仍有很大的可能性弱引用会被分配。
官方文档-https://msdn.microsoft.com/en-us/library/system.weakreference.aspx
7. Lazy<T>使用延迟初始化,可推迟创建大型资源密集型对象或执行资源密集型任务时,在程序生命周期内创建或执行指定类的发生。
publicabstractclassThreadSafeLazyBaseSingleton<T>whereT:new(){privatestaticreadonlyLazy<T>lazy=newLazy<T>(()=>newT());publicstaticTInstance{get{returnlazy.Value;}}}
官方文档-https://msdn.microsoft.com/en-us/library/dd642331(v=vs.110).aspx
8. BigIntegerBigInteger 类型是一个不可变类型,它表示一个任意大的整数,理论上它的值没有上限或下限。这种类型与 .NET Framework 中的其他整型类型不同,这种类型具有自身 MinValue 和 MaxValue 属性指示的范围。
注意:因为 BigInteger 类型是不可变的,并且因为它没有上限或下限,所以对于导致 BigInteger 值变得太大的任何操作,都会引发 OutOfMemoryException。
stringpositiveString="91389681247993671255432112000000";stringnegativeString="-90315837410896312071002088037140000";BigIntegerposBigInt=0;BigIntegernegBigInt=0;posBigInt=BigInteger.Parse(positiveString);Console.WriteLine(posBigInt);negBigInt=BigInteger.Parse(negativeString);Console.WriteLine(negBigInt);
官方文档-https://msdn.microsoft.com/en-us/library/system.numerics.biginteger(v=vs.110).aspx
9.没有官方文档的C#关键字 (__arglist / __reftype / __makeref / __refvalue)一些 C# 关键字是没有官方文档的,没有文档的原因可能是这些关键字没有经过充分测试。但是,这些关键字已被 Visual Studio 编辑器着色并被识别为官方关键字。
你可以使用 __makeref 关键字在变量中创建一个类型化的引用,使用 __reftype 关键字提取由类型化引用表示的变量的原始类型,从 TypedReference 中使用 __refvalue 关键字获取参数值,使用 __arglist 访问参数列表。
inti=21;TypedReferencetr=__makeref(i);Typet=__reftype(tr);Console.WriteLine(t.ToString());intrv=__refvalue(tr,int);Console.WriteLine(rv);ArglistTest.DisplayNumbersOnConsole(__arglist(1,2,3,5,6));
在使用 __arglist 时,需要 ArglistTest 类。
publicstaticclassArglistTest{publicstaticvoidDisplayNumbersOnConsole(__arglist){ArgIteratorai=newArgIterator(__arglist);while(ai.GetRemainingCount()>0){TypedReferencetr=ai.GetNextArg();Console.WriteLine(TypedReference.ToObject(tr));}}}
参考-http://www.nullskull.com/articles/20030114.asp和http://community.bartdesmet.net/blogs/bart/archive/2006/09/28/4473.aspx
10. Environment.NewLine获取当前环境下的换行字符串。
Console.WriteLine("NewLine:{0}firstline{0}secondline{0}thirdline",Environment.NewLine);
官方文档-https://msdn.microsoft.com/en-us/library/system.environment.newline(v=vs.110).aspx
11. ExceptionDispatchInfo保留代码中的某个被捕获的异常。你可以使用 ExceptionDispatchInfo.Throw 方法,这个方法在 System.Runtime.ExceptionServicesnamespace 中。这个方法可用于引发异常并保留原始堆栈的调用过程。
ExceptionDispatchInfopossibleException=null;try{int.Parse("a");}catch(FormatExceptionex){possibleException=ExceptionDispatchInfo.Capture(ex);}if(possibleException!=null){possibleException.Throw();}
被捕获的异常可以在另一个方法或另一个线程中再次抛出。
官方文档-https://msdn.microsoft.com/en-us/library/system.runtime.exceptionservices.exceptiondispatchinfo(v=vs.110).aspx
12. Environment.FailFast()如果你想在不调用任何 finally 块或终结器的情况下退出程序,可以使用 FailFast。
strings=Console.ReadLine();try{inti=int.Parse(s);if(i==42)Environment.FailFast("Specialnumberentered");}finally{Console.WriteLine("Programcomplete.");}
如果 i 等于 42,该 finally 块将不会被执行。
官方文档-https://msdn.microsoft.com/zh-cn/library/ms131100(v=vs.110).aspx
13. Debug.Assert&Debug.WriteIf&Debug.IndentDebug.Assert用于检查条件,如果条件是 false,则输出消息并显示一个显示调用堆栈的消息框。
Debug.Assert(1==0,"Thenumbersarenotequal!Ohmygod!");
如果断言在调试模式下失败,则显示下面的警报,其中包含指定的消息。
Debug.WriteIf- 如果判断的结果是 true,则会将有关调试的信息写入 Listeners 收集中的跟踪侦听器内。
Debug.WriteLineIf(1==1,"ThismessageisgoingtobedisplayedintheDebugoutput!=)");
Debug.Indent/Debug.Unindent– 使得 IndentLevel 逐一递增。
Debug.WriteLine("Whatareingredientstobakeacake?");Debug.Indent();Debug.WriteLine("1.1cup(2sticks)butter,atroomtemperature.");Debug.WriteLine("2cupssugar");Debug.WriteLine("3cupssiftedself-risingflour");Debug.WriteLine("4eggs");Debug.WriteLine("1cupmilk");Debug.WriteLine("1teaspoonpurevanillaextract");Debug.Unindent();Debug.WriteLine("Endoflist");
如果想在调试输出窗口中显示 cake的成分,可以使用上面的代码。
官方文档:Debug.Assert,Debug.WriteIf,Debug.Indent / Debug.Unindent
14. Parallel.For&Parallel.ForeachParallel.For- 执行一个可并行运行迭代的 for 循环。
int[]nums=Enumerable.Range(0,1000000).ToArray();longtotal=0;//Usetypeparametertomakesubtotalalong,notanintParallel.For<long>(0,nums.Length,()=>0,(j,loop,subtotal)=>{subtotal+=nums[j];returnsubtotal;},(x)=>Interlocked.Add(reftotal,x));Console.WriteLine("Thetotalis{0:N0}",total);
Interlocked.Add方法添加两个整数,并用总和替换第一个整数。
Parallel.Foreach- 执行可并行运行迭代的 foreach 操作。
int[]nums=Enumerable.Range(0,1000000).ToArray();longtotal=0;Parallel.ForEach<int,long>(nums,//sourcecollection()=>0,//methodtoinitializethelocalvariable(j,loop,subtotal)=>//methodinvokedbythelooponeachiteration{subtotal+=j;//modifylocalvariablereturnsubtotal;//valuetobepassedtonextiteration},//Methodtobeexecutedwheneachpartitionhascompleted.//finalResultisthefinalvalueofsubtotalforaparticularpartition.(finalResult)=>Interlocked.Add(reftotal,finalResult));Console.WriteLine("ThetotalfromParallel.ForEachis{0:N0}",total);
官方文档:Parallel.For和Parallel.Foreach
15. IsInfinity返回一个值,用于表示某一个数是否为负无穷或正无穷大。
Console.WriteLine("IsInfinity(3.0/0)=={0}.",Double.IsInfinity(3.0/0)?"true":"false");
官方文档-https://msdn.microsoft.com/en-us/library/system.double.isinfinity(v=vs.110).aspx
相关阅读:
是什么优化让 .NET Core 性能飙升?
C#开发人员应该知道的13件事情
是什么让C#成为最值得学习的编程语言
关于葡萄城:
赋能开发者!葡萄城公司成立于 1980 年,是全球领先的集开发工具、商业智能解决方案、管理系统设计工具于一身的软件和服务提供商。西安葡萄城是其在中国的分支机构,面向全球市场提供软件研发服务,并为中国企业的信息化提供国际先进的开发工具、软件和研发咨询服务。葡萄城的控件和软件产品在国内外屡获殊荣,在全球被数十万家企业、学校和政府机构广泛应用。
声明:本站所有文章资源内容,如无特殊说明或标注,均为采集网络资源。如若本站内容侵犯了原著者的合法权益,可联系本站删除。