当前位置: 首页 > news >正文

C# 很少人知道的科技

C# 很少人知道的科技
原文: C# 很少人知道的科技

版权声明:博客已迁移到 http://lindexi.gitee.io 欢迎访问。如果当前博客图片看不到,请到 http://lindexi.gitee.io 访问博客。本文地址 https://blog.csdn.net/lindexi_gd/article/details/79617425

本文来告诉大家在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

重写运算返回

很少人知道实际上重写 == 可以返回任意的类型,而不是只有 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 "不告诉你";

这个代码是可以编译通过的,但是只有在我的设备,然后看了这个博客,可能你也可以在你的设备编译

变量名使用中文

实际上在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

如上面博客,关键在修改callvirtcall,直接修改 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

欢迎加入 dotnet 职业技术学院 https://127.0.0.1/dotnet_campus 使用 Telegram 方法请看 如何使用 Telegram

我搭建了自己的博客 https://lindexi.gitee.io/ 欢迎大家访问,里面有很多新的博客。只有在我看到博客写成熟之后才会放在csdn或博客园,但是一旦发布了就不再更新

如果在博客看到有任何不懂的,欢迎交流,我搭建了 dotnet 职业技术学院 欢迎大家加入

知识共享许可协议
本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。欢迎转载、使用、重新发布,但务必保留文章署名林德熙(包含链接:http://blog.csdn.net/lindexi_gd ),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请与我联系。

posted on 2018-12-25 01:17 NET未来之路 阅读( ...) 评论( ...) 编辑 收藏

转载于:https://www.cnblogs.com/lonelyxmas/p/10171879.html

相关文章:

  • asp.net——公共帮助类
  • 什么是二次开发
  • C++ 解析json串
  • 系统管理员需知的 16 个 iptables 使用技巧
  • $Django python中使用redis, django中使用(封装了),redis开启事务(管道)
  • 《HelloGitHub》第 33 期
  • grep-学习记录
  • 面试题30:包含 min 函数的栈
  • intellij中导入java包
  • Java模仿http请求工具类
  • 数据结构之链表 给定一个链表,判断链表中是否有环。
  • 有点颓废
  • JS判断单、多张图片加载完成
  • webfont在vue中的使用
  • DS树+图综合练习--二叉树之最大路径
  • canvas 绘制双线技巧
  • cookie和session
  • java取消线程实例
  • Laravel 中的一个后期静态绑定
  • magento2项目上线注意事项
  • Vue ES6 Jade Scss Webpack Gulp
  • 成为一名优秀的Developer的书单
  • 初识 webpack
  • 关于 Cirru Editor 存储格式
  • 利用jquery编写加法运算验证码
  • 如何在GitHub上创建个人博客
  • 十年未变!安全,谁之责?(下)
  • 思维导图—你不知道的JavaScript中卷
  • 微信如何实现自动跳转到用其他浏览器打开指定页面下载APP
  • Oracle Portal 11g Diagnostics using Remote Diagnostic Agent (RDA) [ID 1059805.
  • #android不同版本废弃api,新api。
  • #绘制圆心_R语言——绘制一个诚意满满的圆 祝你2021圆圆满满
  • #考研#计算机文化知识1(局域网及网络互联)
  • #中的引用型是什么意识_Java中四种引用有什么区别以及应用场景
  • $forceUpdate()函数
  • (11)工业界推荐系统-小红书推荐场景及内部实践【粗排三塔模型】
  • (2022 CVPR) Unbiased Teacher v2
  • (3)选择元素——(14)接触DOM元素(Accessing DOM elements)
  • (C语言)二分查找 超详细
  • (solr系列:一)使用tomcat部署solr服务
  • (二)hibernate配置管理
  • (一) storm的集群安装与配置
  • (转贴)用VML开发工作流设计器 UCML.NET工作流管理系统
  • *_zh_CN.properties 国际化资源文件 struts 防乱码等
  • ./configure、make、make install 命令
  • .NET : 在VS2008中计算代码度量值
  • .NET 表达式计算:Expression Evaluator
  • .NET 应用架构指导 V2 学习笔记(一) 软件架构的关键原则
  • @ModelAttribute使用详解
  • [ 云计算 | AWS 实践 ] Java 如何重命名 Amazon S3 中的文件和文件夹
  • [100天算法】-每个元音包含偶数次的最长子字符串(day 53)
  • [22]. 括号生成
  • [ANT] 项目中应用ANT
  • [AutoSAR系列] 1.3 AutoSar 架构
  • [GPT]Andrej Karpathy微软Build大会GPT演讲(上)--GPT如何训练