本文來告訴大家在C#很少有人會發現的科技。即使是工作了好多年的老司機也不一定會知道,如果覺得我在騙你,那麼請看看下麵 ...
本文來告訴大家在C#很少有人會發現的科技。即使是工作了好多年的老司機也不一定會知道,如果覺得我在騙你,那麼請看看下麵
因為C#在微軟的幫助,已經從原來很簡單的,到現在的很好用。在10多年,很少人知道微軟做了哪些,我在網上找了很多大神的博客,然後和很多大神聊天,知道了一些科技,所以就在這裡說。如果大家看到這個博客裡面沒有的科技,請告訴我。
無限級判斷空
在 C# 6.0 可以使用??
判斷空,那麼就可以使用下麵代碼
var v1 = "123";
string v2 = null;
string v3 = null;
var v = v1 ?? v2 ?? v3;
實際上可以無限的使用??
using 省略長的定義
例如有這個代碼,使用了很多的 List ,裡面有很多定義
var foo =
new System.Collections.Generic.Dictionary<
System.Collections.Generic.List<System.Collections.Generic.List<string>>, string>();
可以看到需要寫很多代碼,如果這個值作為參數,才是可怕。
一個簡單的方法是使用 using HvcnrclHnlfk= System.Collections.Generic.Dictionary<System.Collections.Generic.List<System.Collections.Generic.List<string>>,string>;
,這個文件里的所有定義都可以使用 using
後面的值可以代替。
var foo = new HvcnrclHnlfk();
辣麽大
實際上我有些不好意思,好像剛剛說的都是大家都知道的,那麼我就要開始寫大家很少知道
Func<string,string, EventHandler> foo = (x, y) => (s, e) =>
{
var button = (Button) s;
button.Left = x;
button.Top = y;
};
Button1.Click += foo(0, -1);
看一下就知道這個定義可以做什麼
千萬不要告訴我,你覺得上面編譯不通過,實際上我用了黑科技
但是不告訴你
衝突的類型
如果遇到兩個命名空間相同的類型,很多時候都是把命名空間全寫
var webControl = new System.Web.UI.WebControls.Control();
var formControl = new System.Windows.Forms.Control();
如果經常使用這兩個控制項,那麼就需要寫空間,代碼很多,但是微軟給了一個坑,使用這個可以不用寫空間
using web = System.Web.UI.WebControls;
using win = System.Windows.Forms;
web::Control webControl = new web::Control();
win::Control formControl = new win::Control();
參見:https://stackoverflow.com/a/9099/6116637
extern alias
如果使用了兩個 dll ,都有相同命名空間和類型,那麼如何使用指定的庫
//a.dll
namespace F
{
public class Foo
{
}
}
//b.dll
namespace F
{
public class Foo
{
}
}
這時就可以使用 extern alias
參見:C#用extern alias解決兩個assembly中相同的類型全名 - fresky - 博客園
字元串
大家看到了 C# 6.0 的$
,是不是可以和@
一起?
var str = "kktpqfThiq";
string foo = $@"換行
{str}";
註意兩個的順序,反過來直接告訴你代碼不能這樣寫
表達式樹獲取函數命名
定義一個類,下麵通過表達式樹從類獲得函數命名
class Foo
{
public void KzcSevfio()
{
}
}
static void Main(string[] args)
{
GetMethodName<Foo>(foo => foo.KzcSevfio());
}
private static void GetMethodName<T>(Expression<Action<T>> action) where T : class
{
if (action.Body is MethodCallExpression expression)
{
Console.WriteLine(expression.Method.Name);
}
}
這樣就可以拿到函數的命名
特殊關鍵字
實際上有下麵幾個關鍵字是沒有文檔,可能只有垃圾微軟的編譯器才知道
__makeref
__reftype
__refvalue
__arglist
不過在 C# 7.2 都可以使用其他的關鍵字做到一些,詳細請看我的 C# 7.0 博客
DebuggerDisplay
如果想要在調試的時候,滑鼠移動到變數顯示他的信息,可以重寫類的 ToString
public sealed class Foo
{
public int Count { get; set; }
public override string ToString()
{
return Count.ToString();
}
}
但是如果 ToString 被其他地方用了,如何顯示?
垃圾微軟告訴大家,使用 DebuggerDisplay 特性
[DebuggerDisplay("{DebuggerDisplay}")]
public sealed class Foo
{
public int Count { get; set; }
private string DebuggerDisplay => $"(count {Count})";
}
他可以使用私有的屬性、欄位,使用方法很簡單
參見Using the DebuggerDisplay Attribute
使用 Unions (C++ 一樣的)
如果看到 C++ 可以使用內聯,不要說 C# 沒有,實際上也可以使用 FieldOffset ,請看下麵
[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;
}
這時就定義了int
變數,修改他就是修改其他的三個
static void Main(string[] args)
{
A a = new A { Int32 = int.MaxValue };
Console.WriteLine(a.Int32);
Console.WriteLine("{0:X} {1:X} {2:X} {3:X}", a.One, a.Two, a.Three, a.Four);
a.Four = 0;
a.Three = 0;
Console.WriteLine(a.Int32);
}
這時會輸出
2147483647
FF FF FF 7F
65535
介面預設方法
實際上可以給介面使用預設方法,使用的方式
public static void Foo(this IF1 foo)
{
//實際上大家也看到是如何定義
}
數字格式
string format = "000;-#;(0)";
string pos = 1.ToString(format); // 001
string neg = (-1).ToString(format); // -1
string zer = 0.ToString(format); // (0)
參見:自定義數字格式字元串
stackalloc
實際上很多人都不知道這個,這是不安全代碼,從棧申請空間
int* block = stackalloc int[100];
參見:stackalloc
調用堆棧
如果需要獲得調用方法的堆棧,可以使用這個文章的方法
class Program
{
static void Main(string[] args)
{
var foo = new Foo();
foo.F1();
}
}
public sealed class Foo
{
public void F1()
{
F2();
}
void F2()
{
var stackTrace = new StackTrace();
var n = stackTrace.FrameCount;
for (int i = 0; i < n; i++)
{
Console.WriteLine(stackTrace.GetFrame(i).GetMethod().Name);
}
}
}
輸出
F2
F1
參見:WPF 判斷調用方法堆棧
指定編譯
如果使用 Conditional 可以讓代碼在指定條件不使用,我寫了這個代碼,在 Release 下就不會使用 F2
public sealed class Foo
{
public Foo F1()
{
Console.WriteLine("進入F1");
return this;
}
[Conditional("DEBUG")]
public void F2()
{
Console.WriteLine("F2");
}
}
簡單讓代碼跑一下
static void Main(string[] args)
{
var foo = new Foo();
foo.F1();
foo.F2();
}
結果是什麼,大家也知道,在 Debug 和 Release 輸出是不相同。但是這麼簡單的怎麼會在這裡說,請大家看看這個代碼輸出什麼
static void Main(string[] args)
{
var foo = new Foo();
foo.F1().F2();
}
實際上在 Release 下什麼都不會輸出,F1 不會被執行
true 判斷
下麵寫個見鬼的代碼
var foo = new Foo(10);
if (foo)
{
Console.WriteLine("我的類沒有繼承 bool ,居然可以這樣寫");
}
沒錯 Foo 沒有繼承 bool 居然可以這樣寫
實際上就是重寫 true ,請看代碼
public class Foo
{
public Foo(int value)
{
_count = value;
}
private readonly int _count;
public static bool operator true(Foo mt)
{
return mt._count > 0;
}
public static bool operator false(Foo mt)
{
return mt._count < 0;
}
}
是不是覺得很多有人這樣寫,下麵讓大家看一個很少人會知道的科技,感謝walterlv
await 任何類型
await "林德熙逗比";
await "不告訴你";
這個代碼是可以編譯通過的,但是只有在我的設備,然後看了這個博客,可能你也可以在你的設備編譯
變數名使用中文
實際上在C#支持所有 Unicode ,所以變數名使用中文也是可以的,而且可以使用特殊的字元
public string H\u00e5rføner()
{
return "可以編譯";
}
本作品採用知識共用署名-非商業性使用-相同方式共用 4.0 國際許可協議進行許可。歡迎轉載、使用、重新發佈,但務必保留文章署名林德熙(包含鏈接:http://blog.csdn.net/lindexi_gd ),不得用於商業目的,基於本文修改後的作品務必以相同的許可發佈。如有任何疑問,請與我聯繫。