C# 很少人知道的科技

本文来告诉大家在C#很少有人会发现的科技。即使是工作了好多年的老司机也不一定会知道这些科技,如果觉得我是在骗你,那么请看看本文的内容。

原本最初 C# 的设计是简单和高效开发的,在经过了这么多年众多公司和开发者的努力下,整个 C# 里面包含了大量有趣的功能。其中一部分功能是针对于某些特殊需求设计的,例如高性能或高并发或无内存回收等。在经过了 10 多年的迭代,很少人能完全了解整个 C# 语言和框架级做了哪些有趣的功能

我在网上找了很多大神的博客,然后和很多大神聊天,知道了一些科技,于是就在本文和大家分享一下。如果大家有了解本博客里面没有收藏的科技,还请告诉我

现在整个 C# 从编译器到运行时都是开源的,所有权在 dotnet 基金会上,全部开源的项目都基于最友好的 MIT 协议和 Apache 2 开源协议,文档协议遵循CC-BY协议。这将允许任何人任何组织和企业任意处置,包括使用,复制,修改,合并,发表,分发,再授权,或者销售。唯一的限制是,软件中必须包含上述版 权和许可提示,后者协议将会除了为用户提供版权许可之外,还有专利许可,并且授权是免费,无排他性的(任何个人和企业都能获得授权)并且永久不可撤销,用户使用.NET 和 C# 完全不用担心收费问题和版权问题,以及后续无法维护问题。而 dotnet 基金会是一个开放的平台,我也是 dotnet 基金会的成员之一。微软在 2020 的时候依然是 dotnet 基金会最大的支持组织

现在最火的 dotnet 仓库是 dotnet csharplang 仓库,当前的 C# 语言特性由整个社区决定,这是一个官方开放用来讨论 C# 语言未来的仓库,天天都有大佬们在讨论语言的特性,欢迎大家加入

接下来让我告诉大家一些很少有人会发现的科技

无限级判断空

在 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 关键词,如在文件的开头添加如下代码

using HvcnrclHnlfk = System.Collections.Generic.Dictionary<System.Collections.Generic.List<System.Collections.Generic.List<string>>,string>;

在添加了上面代码之后,在这个文件里的所有用到如上面很长的定义的代码都可以使用 using 后面的值可以代替,如本文上面使用了 HvcnrclHnlfk 这个词,来看看替换之后的代码长度

var foo = new HvcnrclHnlfk();

辣么大

实际上写到这里我有些不好意思,好像刚刚说的都是大家都知道的,那么我就要开始写大家很少知道的科技

等等,什么是 辣么大 大哇?其实这是 lambda 表达式的翻译

请看看下面这段有趣的代码

            Func<string,string, EventHandler> foo = (x, y) => (s, e) =>{var button = (Button) s;button.Left = x;button.Top = y;};Button1.Click += foo(0, -1);

上面的代码通过一个 lambda 表达式返回一个另一个 lambda 表达式,或者说用一个委托返回另一个委托。这是一个特别有趣的写法,通过函数返回函数的思想可以用来写出一些有趣的逻辑,特别是在多层嵌套的时候

当然使用委托可是会出现另一个问题的,请问下面的代码实际调用的是哪个委托,下面代码的 a 和 b 和 c 都是 Action委托,同时都不是空的

((a + b + c) - (a + c))();

在数学上,其实函数也可以视为变量,很有科技范的 C# 当然也支持如此的功能,将函数包装为委托的时候,可以让委托本身支持加减法哦,只是这个加减法的规则有些诡异。不信,请猜猜上面代码执行了什么函数

冲突的类型

在遇到某些类型,特别是放在 NuGet 上的多个不同的库里面的类型,这些类型有相同的类名,如 Data 或 Control 等很通用的命名的时候,在代码中如果需要同时使用这两个类,就需要补全整个命名空间,如下面代码

var webControl = new System.Web.UI.WebControls.Control();
var formControl = new System.Windows.Forms.Control();

如果经常使用这两个控件,那么就需要写很多补全命名空间的代码,代码很多。好在微软的大佬们给出了一个坑方法,使用这个方法可以不写命名空间,或者说只需要在文件开始 using 一次,请看代码

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 文件里面,这两个程序集都有相同命名空间和类型,那么如何使用指定的库

如下面代码所示,在两个 dll 里面都定义了 F.Foo 类型

//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}";

注意两个的顺序,反过来直接告诉你代码不能这样写

此知识点不再适用,因为在 C# 8.0 的时候,可以按照任意的顺序使用 $ 和 @ 标记。详细请看 $ - 字符串内插 - C# 参考 特别感谢 592844340 群内热心人员勘误

特殊关键字

实际上有下面几个关键字是没有详细的文档,可能只有微软的编译器才知道

__makeref__reftype__refvalue__arglist

不过在 C# 7.2 可以使用其他的关键字做到一些功能,详细请看我的 C# 7.0 博客

使用 Unions (C++ 一样的)

如果看到 C++ 可以使用内联,不要说 C# 没有这个功能,实际上也可以使用 FieldOffset 特性实现和 C++ 一样的内联的功能 ,请看下面代码

[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)
{//实际上大家也看到是如何定义
}

当然了,在 C# 8.0 还有更直接的方法,详细请看 在 C# 中使用默认接口方法安全地更新接口

stackalloc

很多人都不知道这个科技,这是不安全代码,从栈申请空间

int* block = stackalloc int[100]; 

使用的时候需要小心你的栈也许会炸掉

参见:stackalloc

指定编译

这个是一个有趣的特性实现的功能,是一个编译器技术,写给编译器看的特性。使用 Conditional 特性可以让代码在指定条件不使用,如下面的代码,规定了只有在 DEBUG 宏定义的时候才让 F2 方法生效。因此在 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 的新的语法

例如下面的内部方法返回自身

方法返回自身可以接近无限调用

有一天我看到了下面的代码,你猜小伙伴用什么代码定义了 Foo 这个代码?

Foo()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()();

其实只需要定义一个委托,用内部方法实现委托,因为内部方法是可以返回自身,于是就可以使用5行代码写出 Foo 的定义

        delegate Foo Foo(); // 定义委托static void Main(string[] args)
{Foo Foo() // 定义内部方法{return Foo;}
}

不过括号还不可以无限使用,因为编译器有一个表达式的长度限制

无限长度的委托调用

试试这个代码,也许你可以无限写下去,只要 Roslyn 不会炸就可以

 delegate Fx Fx(Fx fx);Fx fx = fx => fx => fx => fx => fx => fx => fx => fx => fx => fx => fx => fx => fx => fx => fx => fx =>fx => fx => fx => fx => fx => fx => fx => fx => fx => fx;

以下部分准确来说是 .NET 提供的功能,请问 C# 和 .NET 是什么关系?其实我也无法用一两句话说清,扔掉了 .NET 依然可以用 C# 写程序,反过来扔掉 C# 也依然能用 .NET 写程序

表达式树获取函数命名

定义一个类,下面通过表达式树从类获得函数命名

    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);}}

这样就可以拿到函数的命名

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

数字格式

string format = "000;-#;(0)";string pos = 1.ToString(format);     // 001
string neg = (-1).ToString(format);  // -1
string zer = 0.ToString(format);     // (0)

参见:自定义数字格式字符串

调用堆栈

如果需要获得调用方法的堆栈,可以使用这个文章的方法

  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 判断调用方法堆栈

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

特别感谢

特别感谢 吕毅 - walterlv 提供的逗比代码

特别感谢队长提供的 .NET Core也是国产化信息系统开发的重要选项 - 张善友 - 博客园 博客。本文开头为了更准确的描述,于是抄了队长的博客内容

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/307325.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Typescript前端接口联调自动化的探究与实践

源宝导读&#xff1a;Web应用程序一般都是前后端分离的基本架构&#xff0c;而前后端很可能分别是两拨人分别开发&#xff0c;前后端的接口连调成为高频沟通的对象&#xff0c;开发内耗最大的也在这个环节。本文将分享如何基于OpenAPI将前后端接口协议标准化和自动化&#xff0…

leetcode51. N 皇后(java详解)

一:题目 二:上码 class Solution {/**思路:1.先说我们选用的数据结构;我们是选取的是List<List<string>> ans 来存每次的结果;我们在创建这个二维矩阵的时候用的是char的二维数组,那么的话等到我们得到一种可行解的时候 将char的二维数组每一行转换成 String 并存…

程序员如何跨越35岁危机?这篇给点干货建议!

职场&认知洞察 丨 作者 / findyi这是findyi公众号的第83篇原创文章这两天在我的读者群里做了一个职业小调研&#xff0c;发现关注我公众号的70%以上都是程序员。毕竟程序员吸引程序员&#xff0c;这也算猿粪吧&#xff0c;哈哈。这个小调研也引发大家对程序员行业的激烈探讨…

leetcode455. 分发饼干

一:题目 二:上码 class Solution {public int findContentChildren(int[] g, int[] s) {int ans 0;int gIndex 0;int sIndex 0;Arrays.sort(g);Arrays.sort(s);while (gIndex < g.length && sIndex < s.length) {if (s[sIndex] > g[gIndex]) gIndex; //只…

写了多年代码,你会 StackOverflow 吗

写了多年代码&#xff0c;你会 StackOverflow 吗Intro准备写一个傻逼代码的系列文章&#xff0c;怎么写 StackOverflow 的代码&#xff0c;怎么写死锁代码&#xff0c;怎么写一个把 CPU 跑满&#xff0c;怎么写一个 OutOfMemory 的代码。今天主要来看 StackOverflow&#xff0c…

C#实现迭代器

迭代器模式&#xff08;Iterator&#xff09;&#xff0c;提供一种方法顺序访问一个聚合对象中的各种元素&#xff0c;而又不暴露该对象的内部表示。C#中使用IEnumerator接口实现&#xff0c;Java中使用Iterator接口实现&#xff0c;其中原理都差不多&#xff0c;下面我就用C#代…

从CLR GC到CoreCLR GC看.NET Core为云而生

内存分配概要前段时间在园子里看到有人提到了GC学习的重要性&#xff0c;很赞同他的观点。充分了解GC可以帮助我们更好的认识.NET的设计以及为何在云原生开发中.NET Core会占有更大的优势&#xff0c;这也是一个程序员成长到更高层次所需要经历的过程。在认识GC的过程中&#x…

springboot邮件发送(牛客论坛项目之QQ邮箱发送)

一:邮箱发送原理 1:狂神图解 张三通过smtp协议连接到Smtp服务器&#xff0c;然后发送一封邮件给网易的邮件服务器网易分析发现需要去QQ的邮件服务器&#xff0c;通过Smtp协议将邮件转投给QQ的Smtp服务器QQ将接收到的邮件存储在456789qq.com这个邮件账号的空间中李四通过Pop3协…

如果淘宝双十一架构用. Net Core,如何“擒住”高并发、高可用、低延迟?

电商的秒杀和抢购&#xff0c;对我们来说&#xff0c;都不是一个陌生的东西。然而&#xff0c;从技术的角度来说&#xff0c;这对于Web系统是一个巨大的考验。当一个Web系统&#xff0c;在一秒钟内收到数以万计甚至更多请求时&#xff0c;系统的优化和稳定至关重要。缓存技术是…

.NET5在开发平台上远优于Java,如何发挥优势?

上周.NET5 RC2已发布&#xff0c;.NET5已经肉眼可见的即将到来&#xff0c;令人期待&#xff01;从.NET Framework到.NET Core再到.NET5&#xff0c;能看到诸多开发者和公司都在积极拥抱新技术。对比Java&#xff0c;国内主流开发都还停留在Java8&#xff0c;在云原生的互联网时…

leetcode122. 买卖股票的最佳时机 II

一:题目 二&#xff1a;上码 class Solution {/**思路:1.局部最优:我们买入当前股票等哪天遇见最大值的时候买出 赚最大利润2.全局最优:局部最优推出全局最优3.这个利润是可以被分解的 7 1 5 10利润: -6 4 5那么最大利润是459其实就是1买入10卖出,但是我们可以在5这天…

多重继承和菱形问题

翻译自 John Demetriou 2018年4月8日 的文章 《Multiple Inheritance And The Diamond Problem》[1]开篇之前&#xff0c;我假设每个人都知道在面向对象编程中继承是什么&#xff0c;以及它能提供什么好处。我不会深入探究对象继承的基础知识。这篇文章更关注于多重继承和它所面…

Jekins持续集成在ERP研发中的应用实践

源宝导读&#xff1a;“持续集成”是敏捷最佳实践中&#xff0c;保证高质量交付的关键环节之一。本文将介绍明源云ERP系统在研发过程中&#xff0c;应用Jekins平台完成持续集成自动构建的实践。一、认识持续集成持续集成是一种软件开发实践&#xff0c;即团队开发成员经常集成他…

leetcode45. 跳跃游戏 II(java详解)

一:题目 二:上码 class Solution {public int jump(int[] nums) {int ans 0;int curIndex 0;//当前统计出来的可以移动的最远距离的下标int nextIndex 0;//在到达 当前最远距离下标的这段距离内 我们统计出的可以达到的最远距离//如果在统计的过程中 其覆盖范围已经大于数组…

Ids4 认证保护 API 方案更新

壹时刻保持学习的喜悦可能你咋一看这个标题不知道什么意思&#xff0c;其实我也没想好怎么表达&#xff0c;因为是一个特别简单的小知识点。先说下为什么突然说到了Ids4&#xff1f;这几天大家都知道&#xff0c;我在视频《微服务之eShop讲解》&#xff0c;目前讲到了购物车微服…

dotNet Core 3.1 使用 Aspose (部署 Docker)

在之前的文章《dotNET Core中使用Aspose&#xff08;部署Docker&#xff09;》中介绍了在 dotNet Core2.1 中使用 Aspose &#xff0c;并部署到 Docker 中&#xff0c;现在 dotNET Core 升级到了 3.1 &#xff0c;Docker 镜像发生了变化&#xff0c;一些依赖的安装也有些变化。…

MySQL之一条Update的执行流程

文章目录1:执行的语句2:在更新操作中流程中特有的部分(1):redo log&#xff08;重做日志&#xff09;(2):binlog&#xff08;归档日志&#xff09;(3):Redo日志跟binlog日志的区别2:执行流程1:执行的语句 update T set c c 1 where ID 2;2:在更新操作中流程中特有的部分 (…

教你打入clr内部: 配置windows上的windbg,linux上的lldb

一&#xff1a;背景1. 讲故事前几天公众号里有位兄弟看了几篇文章之后&#xff0c;也准备用windbg试试看&#xff0c;结果这一配就花了好几天&#xff0c;(づ╥﹏╥)づ&#xff0c;我想也有很多跃跃欲试的朋友在配置的时候肯定会遇到这样和那样的问题&#xff0c;所以我觉得有必…

leetcode周赛6076. 表示一个折线图的最少线段数

气死爹了 用C过不去 换成Java 过了 一:题目 二:上码 class Solution {public int minimumLines(int[][] stockPrices) {Arrays.sort(stockPrices,(o1,o2)->o1[0]-o2[0]);int n stockPrices.length;if (n 1) return 0;int ans 1;for (int i 0; i < n-2; i) {int k1 …

使用代码片段的正确姿势,打造高效的vscode开发环境

全文3928字&#xff0c;阅读时间 10分钟&#xff0c;未来节约时间 15分钟/每天代码片段&#xff08;code snippet&#xff09; 相信大家都或多或少有接触过。在完成一个项目以后&#xff0c;往往都会写出许多有价值的代码&#xff0c;或是绞尽脑汁解决的难题&#xff0c;或是灵…