您的位置:首页 > 编程语言 > C#

C# 很少人知道的科技

2018-03-19 20:57 357 查看
本文来告诉大家在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 ),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请与我联系
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: