目錄
1. ObsoleteAttribute
2. 設置默認值屬性: DefaultValueAttribute
3. DebuggerBrowsableAttribute
4. ??運算符
5. Curry 及 Partial 方法
6. WeakReference
7. Lazy
8. BigInteger
9. 非官方關鍵字:__arglist __reftype __makeref __refvalue
10. Environment.NewLine
11. ExceptionDispatchInfo
12. Environment.FailFast
13. Debug.Assert, Debug.WriteIf 及 Debug.Indent
14. Parallel.For 及 Parallel.Foreach
15. IsInfinity方法
本文介紹了.Net 常被忽略,但卻非常有用戶的15個功能,包含ObsoleteAttribute,DefaultValueAttribute,DebuggerBrowsableAttribute,?運算符,Curry 及 Partial 方法…
ObsoleteAttribute: 可適用於除程序集、模塊、參數或返回值以外的所有程序元素。將元素標記為 Obsolete 可實現通知用戶的功能,表明該元素在產品之後的新版本中會被移除。
Message屬性包含一個字符串,可獲取變通方法消息,是對可選程序元素的說明。
IsError屬性:是Bool 類型,如果將值設為“True”,則編譯器會將使用已過時的程序元素視為錯誤。
1: public static class ObsoleteExample
2: {
3: // Mark OrderDetailTotal As Obsolete.
4: [ObsoleteAttribute("This property (DepricatedOrderDetailTotal) is obsolete. Use InvoiceTotal instead.", false)]
5: public static decimal OrderDetailTotal
6: {
7: get
8: {
9: return 12m;
10: }
11: }
12:
13: public static decimal InvoiceTotal
14: {
15: get
16: {
17: return 25m;
18: }
19: }
20:
21: // Mark CalculateOrderDetailTotal As Obsolete.
22: [ObsoleteAttribute("This method is obsolete. Call CalculateInvoiceTotal instead.", true)]
23: public static decimal CalculateOrderDetailTotal()
24: {
25: return 0m;
26: }
27:
28: public static decimal CalculateInvoiceTotal()
29: {
30: return 1m;
31: }
32: }
如果運行程序,編譯器就會報錯以及Warning。
1: Console.WriteLine(ObsoleteExample.OrderDetailTotal);
2: Console.WriteLine();
3: Console.WriteLine(ObsoleteExample.CalculateOrderDetailTotal());
1: public class DefaultValueAttributeTest
2: {
3: public DefaultValueAttributeTest()
4: {
5: // Use the DefaultValue propety of each property to actually set it, via reflection.
6: foreach (PropertyDescriptor prop in TypeDescriptor.GetProperties(this))
7: {
8: DefaultValueAttribute attr = (DefaultValueAttribute)prop.Attributes[typeof(DefaultValueAttribute)];
9: if (attr != null)
10: {
11: prop.SetValue(this, attr.Value);
12: }
13: }
14: }
15:
16: [DefaultValue(25)]
17: public int Age { get; set; }
18:
19: [DefaultValue("Anton")]
20: public string FirstName { get; set; }
21:
22: [DefaultValue("Angelov")]
23: public string LastName { get; set; }
24:
25: public override string ToString()
26: {
27: return string.Format("{0} {1} is {2}.", this.FirstName, this.LastName, this.Age);
28: }
29: }
表示成員是否在Debugger 變量窗口顯示以及如何顯示。
1: public static class DebuggerBrowsableTest
2: {
3: private static string squirrelFirstNameName;
4: private static string squirrelLastNameName;
5:
6: // The following DebuggerBrowsableAttribute prevents the property following it
7: // from appearing in the debug window for the class.
8: [DebuggerBrowsable(DebuggerBrowsableState.Never)]
9: public static string SquirrelFirstNameName
10: {
11: get
12: {
13: return squirrelFirstNameName;
14: }
15: set
16: {
17: squirrelFirstNameName = value;
18: }
19: }
20:
21: [DebuggerBrowsable(DebuggerBrowsableState.Collapsed)]
22: public static string SquirrelLastNameName
23: {
24: get
25: {
26: return squirrelLastNameName;
27: }
28: set
29: {
30: squirrelLastNameName = value;
31: }
32: }
33: }
逐步調試程序時,就會發現代碼會一直在執行:
1: DebuggerBrowsableTest.SquirrelFirstNameName = "Hammy";
2: DebuggerBrowsableTest.SquirrelLastNameName = "Ammy";
?? 運算符稱作 null 合並運算符。如果此運算符的左操作數不為 null,則此運算符將返回左操作數;否則返回右操作數,如果在嘗試將可以為null 值的類型分配給不可以為null值的類型時,沒有使用??運算符,則會生成編譯時的錯誤。如果使用強制轉換,且當前未定義可以為 null 值的類型,則會引發 InvalidOperationException 異常。
1: int? x = null;
2: int y = x ?? -1;
3: Console.WriteLine("y now equals -1 because x was null => {0}", y);
4: int i = DefaultValueOperatorTest.GetNullableInt() ?? default(int);
5: Console.WriteLine("i equals now 0 because GetNullableInt() returned null => {0}", i);
6: string s = DefaultValueOperatorTest.GetStringValue();
7: Console.WriteLine("Returns 'Unspecified' because s is null => {0}", s ?? "Unspecified");
Curry 方法是把接受多個參數的函數變換成接受一個單一參數(最初函數的第一個參數)的函數,並且返回接受余下的參數且返回結果的新函數的技術。
1: public static class CurryMethodExtensions
2: {
3: public static Func<A, Func<B, Func<C, R>>> Curry<A, B, C, R>(this Func<A, B, C, R> f)
4: {
5: return a => b => c => f(a, b, c);
6: }
7: }
如果無法確定成員函數的返回類型可使用Var執行。
Partial—Partial類型允許我們將一個類、接口或結構分成好幾個部分,分別實現在幾個不同的.cs 文件中。關鍵字partial是一個上下文關鍵字,只有和class、struct、interface放在一起時才有關鍵字的含義。因此partial 的引入不會影響現有代碼中名稱為partial的變量。
1: public static class CurryMethodExtensions
2: {
3: public static Func<C, R> Partial<A, B, C, R>(this Func<A, B, C, R> f, A a, B b)
4: {
5: return c => f(a, b, c);
6: }
7: }
Weak Reference 表示類型化弱引用,即在引用對象的同時仍然允許垃圾回收來回收該對象。如果你想使用該引用,可以設置為強引用類型,保證該對象不被回收。
1: WeakReferenceTest hugeObject = new WeakReferenceTest();
2: hugeObject.SharkFirstName = "Sharky";
3: WeakReference w = new WeakReference(hugeObject);
4: hugeObject = null;
5: GC.Collect();
6: Console.WriteLine((w.Target as WeakReferenceTest).SharkFirstName);
Lazy<T>提供對延遲一些大資源或資源緊張的對象的初始化的支持。在程序的生存期內,特別是在這種方式創建或執行可能不發生使用延遲初始化延遲一種或大量占用資源的對象的創建、資源的任務的執行。
1: public abstract class ThreadSafeLazyBaseSingleton<T>
2: where T : new()
3: {
4: private static readonly Lazy<T> lazy = new Lazy<T>(() => new T());
5:
6: public static T Instance
7: {
8: get
9: {
10: return lazy.Value;
11: }
12: }
13: }
1: string positiveString = "91389681247993671255432112000000";
2: string negativeString = "-90315837410896312071002088037140000";
3: BigInteger posBigInt = 0;
4: BigInteger negBigInt = 0;
5:
6: posBigInt = BigInteger.Parse(positiveString);
7: Console.WriteLine(posBigInt);
8: negBigInt = BigInteger.Parse(negativeString);
9: Console.WriteLine(negBigInt);
第9條講 的關鍵字官方文檔並沒有記錄,可能正在測試中。然而這些關鍵字豐富了Visual Studio 編輯器的功能,也能被識別。
開發人員可以使用__makeref關鍵字創建變量。使用__refvalue修飾變量可以從 TypedReference中獲得變量值。__arglist關鍵字與params的作用相同,可以訪問參數列表。
1: int i = 21;
2: TypedReference tr = __makeref(i);
3: Type t = __reftype(tr);
4: Console.WriteLine(t.ToString());
5: int rv = __refvalue( tr,int);
6: Console.WriteLine(rv);
7: ArglistTest.DisplayNumbersOnConsole(__arglist(1, 2, 3, 5, 6));
為了使用__arglist, 需要定義ArglistTest 類
1: public static class ArglistTest
2: {
3: public static void DisplayNumbersOnConsole(__arglist)
4: {
5: ArgIterator ai = new ArgIterator(__arglist);
6: while (ai.GetRemainingCount() > 0)
7: {
8: TypedReference tr = ai.GetNextArg();
9: Console.WriteLine(TypedReference.ToObject(tr));
10: }
11: }
12: }
獲取為此環境定義的換行字符串。
1: Console.WriteLine("NewLine: {0} first line{0} second line{0} third line", Environment.NewLine);
表示捕獲特定點的異常情況。可以使用ExceptionDispatchInfo.Throw 方法,命名空間為System.Runtime.ExceptionServices。
1: ExceptionDispatchInfo possibleException = null;
2:
3: try
4: {
5: int.Parse("a");
6: }
7: catch (FormatException ex)
8: {
9: possibleException = ExceptionDispatchInfo.Capture(ex);
10: }
11:
12: if (possibleException != null)
13: {
14: possibleException.Throw();
15: }
如果想退出程序,且不需要調用任何Finally 塊或Finalizers,可以使用FailFast。
1: string s = Console.ReadLine();
2: try
3: {
4: int i = int.Parse(s);
5: if (i == 42) Environment.FailFast("Special number entered");
6: }
7: finally
8: {
9: Console.WriteLine("Program complete.");
10: }
Debug.Assert——檢查條件;如果條件為 false,則顯示一個消息框,其中會顯示調用堆棧。Debug.Assert盡在調試版中有效,在發布版中如果要執行斷言,則使用Trace.Assert。
Debug.Assert(1 == 0, "The numbers are not equal! Oh my god!");
如果Assert在Debug模式下失敗,則會顯示下圖:
多線程的情況下較為常用。
Parallel.For—執行循環,迭代可以運行。
1: int[] nums = Enumerable.Range(0, 1000000).ToArray();
2: long total = 0;
3:
4: // Use type parameter to make subtotal a long, not an int
5: Parallel.For<long>(0, nums.Length, () => 0, (j, loop, subtotal) =>
6: {
7: subtotal += nums[j];
8: return subtotal;
9: },
10: (x) => Interlocked.Add(ref total, x)
11: );
12:
13: Console.WriteLine("The total is {0:N0}", total);
Interlocked.Add 方法將兩個整型值相加,並將結果保存到第一個數值,可以作為原子操作。
Parallel.Foreach——執行 foreach(在 Visual Basic 中為 For Each)操作,其中在 Partitioner 上可能會並行運行迭代。
判斷數值的正負情況。
1: Console.WriteLine("IsInfinity(3.0 / 0) == {0}.", Double.IsInfinity(3.0 / 0) ? "true" : "false");
原文鏈接:http://www.codeproject.com/Articles/1021335/Top-Underutilized-Features-of-NET