C# 很少人知道的科技
本文来告诉大家在C#很少有人会发现的科技。即使是工作了好多年的老司机也不一定会知道,如果觉得我在骗你,那么请看看下面
因为C#在微软的帮助,已经从原来很简单的,到现在的很好用。在10多年,很少人知道微软做了哪些,我在网上找了很多大神的博客,然后和很多大神聊天,知道了一些科技,所以就在这里说。如果大家看到这个博客里面没有的科技,请告诉我
无限级判断空
在 C# 6.0 可以使用??
判断空,那么就可以使用下面代码
var v1 = "123";string v2 = null;string v3 = null;var v = v1 ?? v2 ?? v3;
实际上可以无限的使用??
判断前面一个函数为空,那么问题来了,下面的代码输出的是多少?
var n = 2 + foo?.N ?? 1;
上面代码的 foo 就是空的,那么 n 是多少?是 1 还是 2 还是 3 还是空?
想要了解这道题的推导过程请看C# 高级面试题 里面写了很多老司机都不一定能解出
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);
看一下就知道这个定义可以做什么
当然使用委托可是会出现这个问题,请问下面的代码实际调用的是哪个委托,下面代码的 a 和 b 和 c 都是 Action
委托,同时都不是空的
((a + b + c) - (a + c))();
冲突的类型
如果遇到两个命名空间相同的类型,很多时候都是把命名空间全写
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.dllnamespace F
{public class Foo{}
}//b.dllnamespace 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 clas 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
重写运算返回
很少人知道实际上重写 ==
可以返回任意的类型,而不是只有 bool ,请看下面代码
是可以编译通过的,因为我重写运算
class Foo{public int Count { get; set; }public static string operator ==(Foo f1, Foo f2){if (f1?.Count == f2?.Count){return "lindexi";}return "";}public static string operator !=(Foo f1, Foo f2){return "";}}
可以重写的运算很多,返回值可以自己随意定义。
await 任何类型
await "林德熙逗比";await "不告诉你";
这个代码是可以编译通过的,但是只有在我的设备,然后看了这个博客,可能你也可以在你的设备编译
其实 await 是可以写很多次的,如下面代码
await await await await await await await await await await await await await await await await await await await await await await await "林德熙逗比";
变量名使用中文
实际上在C#支持所有 Unicode ,所以变量名使用中文也是可以的,而且可以使用特殊的字符
public string H\u00e5rføner(){return "可以编译";}
if this == null
一般看到下面的代码都觉得是不可能
if (this == null) Console.WriteLine("this is null");
如果在 if 里面都能使用 this == null 成立,那么一定是vs炸了。实际上这个代码还是可以运行。
在一般的函数,如 Foo ,在调用就需要使用f.Foo()
的方法,方法里 this 就是 f ,如果 f == null
那么在调用方法就直接不让运行,如何到方法里的判断
f.Foo(); //如果 f 为空,那么这里就不执行void Foo()
{// 如果 this 为空,怎么可以调用这个方法if (this == null) Console.WriteLine("this is null");
}
实际上是可以做的,请看(C#)if (this == null)?你在逗我,this 怎么可能为 null!用 IL 编译和反编译看穿一切 - walterlv
如上面博客,关键在修改callvirt
为 call
,直接修改 IL 可以做出很多特殊的写法。
那么这个可以用在哪里?可以用在防止大神反编译,如需要使用下面逻辑
//执行的代码//不执行的代码
if(true)
{//执行的代码
}
else
{//不执行的代码
}
但是直接写 true 很容易让反编译看到不使用代码,而且在优化代码会被去掉,所以可以使用下面代码
if(this == null)
{//执行的代码
}
else
{//不执行的代码
}
实际在微软代码也是这样写,点击string可以看到微软代码
重载的运算符
实际上我可以将 null 强转某个类,创建一个新的对象,请看代码
Fantastic fantastic = (FantasticInfo) null;
fantastic.Foo();
这里的 FantasticInfo 和 Fantastic 没有任何继承关系,而且调用 Foo 不会出现空引用,也就是 fantastic 是从一个空的对象创建出来的。
是不是觉得上面的科技很黑,实际原理没有任何黑的科技,请看代码
public class Fantastic{private Fantastic(){}public static implicit operator Fantastic(FantasticInfo value) => new Fantastic();public void Foo(){}}public class FantasticInfo{}
通过这个方式可以让开发者无法直接创建 Fantastic 类,而且在不知道 FantasticInfo 的情况无法创建 Fantastic 也就是让大家需要了解 FantasticInfo 才可以通过上面的方法创建,具体请看只有你能 new 出来!.NET 隐藏构造函数的 n 种方法(Builder Pattern / 构造器模式) - walterlv
课件链接: https://r302.cc/J4gxOX
当然还有新的 C# 7.0 和 C# 8.0 的新的语法
欢迎加入 dotnet 职业技术学院 https://t.me/dotnet_campus 使用 Telegram 方法请看 如何使用 Telegram
本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。欢迎转载、使用、重新发布,但务必保留文章署名林德熙(包含链接:http://blog.csdn.net/lindexi_gd ),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请与我联系。
C# 很少人知道的科技相关推荐
- enfp工具箱怎么用_5个很少人知道的黑科技工具箱,功能奇妙,一个顶十个用
原标题:5个很少人知道的黑科技工具箱,功能奇妙,一个顶十个用 平时我们上网或者在使用手机的时候,是不是因为各种各样的操作需要下载很多各式各样的软件?今天要来说说5个实用的黑科技工具箱,手机端网页端都有 ...
- 搞模具的想转行学计算机,为什么很少人去做模具设计学徒,看看这里你就明白了!...
原标题:为什么很少人去做模具设计学徒,看看这里你就明白了! 模具是工业之母,我们生活中很多东西都是用模具生产的,由于需求量巨大,只有用模具批量生产才能让产品达到量产,提高效率,降低成本.目前工业发展迅 ...
- python中文名字叫什么-Python为什么取名为Python,很少人知道
原标题:Python为什么取名为Python,很少人知道 打开世界编程语言排行榜,出现在榜单上的语言名称多半都让人一头雾水.一些编程语言的作者会以「这种语言是什么」来命名语言,比如 BASIC.COB ...
- 相片打印机原理_激光照片打印机的原理 为什么很少人用激光照片打印机打印照片...
激光照片打印机是利用激光扫描,在硒鼓上形成电荷潜影,然后吸附墨粉,再将墨粉转印到打印纸上,只不过黑白激光打印机只有一种黑色墨粉,而彩色激光打印机要使用黄.品.青.黑四种颜色的墨粉. 该图片由注册用户& ...
- 为什么很少人用redmine_为什么中文不能用来编程呢?其实还有这些原因!看完长见识了...
今天小编带大家来了解一下编程的问题. 编程就是让计算机为解决某个问题而使用某种程序设计语言编写程序代码,并最终得到结果的过程.那么有些小伙伴就很困惑了,为什么我们编程的时候为什么中文不能用来编程呢? ...
- android电视打开ppt,很少人知道的3种智能电视演示PPT的方法
原标题:很少人知道的3种智能电视演示PPT的方法 演示PPT,通常是在投影上,但随着大屏智能电视的火热和普及,越来越多的办公室以大屏智能电视取代投影,成为办公室不可或缺的生产力.今天就以60吋酷开K6 ...
- 很少人知道但很有用的 Linux 命令
Linux命令行吸引了大多数Linux爱好者.一个正常的Linux用户一般掌握大约50-60个命令来处理每日的任务.Linux命令和它们的转换对于Linux用户.Shell脚本程序员和管理员来说是最有 ...
- 很少人知道的Linux命令
Linux命令行吸引了大多数Linux爱好者.一个正常的Linux用户一般掌握大约50-60个命令来处理每日的任务.Linux命令和它们的转换对于Linux用户.Shell脚本程序员和管理员来说是最有 ...
- 这10个超厉害的工具堪称神器,却很少人知道!
只需要像打字一样就能生成多种不同动效的gif图片的神器想要了解一下吗?一键搜索所有免费免版权商用图库的神器呢?以及动动鼠标就能生成酷炫背景图的神器....最近小白发现了一些超厉害的工具,堪称在线神器, ...
最新文章
- 使用 markdown-it 解析 markdown 代码(读 VuePress 三)
- 工厂设计模式——简单工厂模式——未完待续
- jQuery的核心函数
- c++实现高精度乘法!
- Visual Studio 2008 完全卸载 - C语言零基础入门教程
- c语言辗转相除法求最大公约数_趣味探究:妙法求“最大公因数”,比书上难一点,你敢挑战吗?(适合56年级)...
- java 阻塞 socket_java socket非阻塞I/O
- UVa 129 - Krypton Factor(回溯法)
- .NET_.NET Copy Web 部署概念_01-3
- Mybatis Plus简介_代码_以及文档地址_以及前置知识---Mybatis Plus工作笔记001
- easyui datagrid 列中的checkbox 动态绑定
- Flash 应用:大智慧flash版本
- linux非对称内存,CryptoAPI与OpenSSL RSA非对称加密解密(PKCS1 PADDING)交互
- 蓝桥杯十大常见天阶功法——炎之呼吸.叁之型.动态规划--(上篇)
- 云计算设计模式翻译(五):Compute Resource Consolidation Pattern
- 2020_CIKM_Partial Relationship Aware Influence Diffusion via a Multi-channel Encoding Scheme for Soc
- 数据分析实际案例之:pandas在泰坦尼特号乘客数据中的使用
- 《网页美工设计Photoshop+Flash+Dreamweaver从入门到精通》——1.6 网页配色安全
- 【手绘漫画】图解LeetCode之两两交换链表中的节点(LeetCode 24)
- python制作我的世界_python的pygame制作的2D我的世界