C# 这些年来受欢迎的特性

原文地址:http://www.dotnetcurry.com/csharp/1411/csharp-favorite-features

在写这篇文章的时候,C# 已经有了 17 年的历史了,可以肯定地说它并没有去任何地方。C# 语言团队不断致力于开发新特性,改善开发人员的体验。

在这篇文章中,我在介绍 C# 历史版本的同时分享我最喜欢的特性,在强调实用性的同时展示其优点。

C# 1.0

C#1.0 (ISO-1) 确实算是语言,却没有什么令人兴奋的,缺少许多开发人员喜欢的特性。仔细一想,我能说得出喜欢的只有一个特别的特性 - 隐式和显式接口实现 。

接口在现今开发 C# 的过程中仍然流行使用,以下面的 IDateProvider 接口为例。

public interface IDateProvider{   
 DateTime GetDate(); }

没有什么特别的,现在着手两种实现方式 - 其中第一种是隐式实现,如下:

public class DefaultDateProvider : IDateProvider{    
public DateTime GetDate()    {    
   return DateTime.Now;} }

第二种实现是如下的显式实现方式:

public class MinDateProvider : IDateProvider{   
 DateTime IDateProvider.GetDate(){        return DateTime.MinValue;} }

注意显式实现如何省略访问修饰符。此外,方法名称被写为 IDateProvider.GetDate() ,它将接口名称作为限定符的前缀。
这两件事情使得调用更明确的。

显式接口实现的一个很好的方面是它强制消费者依赖于接口。显式实现接口的实例对象必须使用接口本身,而没有其他可用的接口成员!

但是,当您将其声明为接口或将此实现作为期望接口的参数传递时,成员将如预期可用。

这是特别有用的方面,因为它强制使用接口。通过直接使用接口,不会将代码耦合到底层实现。同样,明确的接口实现避免命名或方法签名歧义 - 并使单个类可以实现具有相同成员的多个接口。

Jeffery Richter 在他 CLR via C# 一书中提醒了我们显式的接口实现两个主要问题是值类型实例在投射到一个接口和明确实现的方法时将被装箱,同时不能被派生类调用。

请记住,装箱和拆箱会影响性能。任何编程中,你应该评估用例来确保善用工具。

C# 2.0

作为参考,我将列出C# 2.0 (ISO-2) 的所有特性。

  • 匿名方法

  • 协变和逆变

  • 泛型

  • 迭代器

  • 可空类型

  • 部分类型

我最在最喜欢 泛型 还是 迭代器 之间的摇摆,对我来说这是一个非常困难的选择,最终还是更喜欢泛型,顺便说说其中缘由。

因为相比于写迭代器,我更频繁地使用泛型。在 C# 中很多 SOLID 编程原则都是使用泛型来强化的,同样它也有助于保持代码的 干爽。不要误解我的意思,我同时也写了一些迭代器,在 C# 同样中值得采用!

让我们更详细地看看泛型。

编者注:学习如何 在 C# 中 使用泛型来提高应用程序的可维护性

泛型向.NET Framework引入了类型参数的概念,这使得可以设计类和方法来推迟一个或多个类型的规范,直到类或方法被客户端代码声明和实例化为止。

让我们想象一下,我们有一个名为 DataBag 的类,作为一个数据包。它可能看起来像这样:

public class DataBag{  
 public void Add(object data)    {        // omitted for brevity...}             }

起初看起来这似乎是一个很棒的想法,因为你可以在这个 DataBag 的实例中添加任何东西。但是当你真正想到这意味着什么的时候,会觉得相当骇人。

所有添加的内容都隐式地包装为 System.Object 。此外,如果添加了值类型,则会发生装箱。这些是您应该注意的性能考虑事项。

泛型解决了这一切,同时也增加了类型安全性。让我们修改前面的例子,在类中包含一个类型参数 T ,并注意方法签名的变化。

public class DataBag{    
public void Add(T data)    {        // omitted for brevity...} }

例如现在一个 DataBag 实例将只允许调用者添加 DateTime 实例。要类型安全,没有装箱或拆箱 ... 让更美好的事情发生。

泛型类型参数也可以被约束。通用约束是强有力的,因为它们必须遵守相应的约束条件,只允许有限范围的可用类型参数。

有几种编写泛型类型参数约束的方法,请考虑以下语法:

public class DataBag where T : struct { /* T 值类型 */ }
public class DataBag where T : class { /* T 类、接口、委托、数组 */ }
public class DataBag where T : new() { /* T 有无参构造函数 */ }
public class DataBag where T : IPerson { /* T 继承 IPerson */ }
public class DataBag where T : BaseClass { /* T 派生自 BaseClass */ }
public class DataBag where T : U { /* T 继承 U, U 也是一个泛型参数 */ }

多个约束是允许的,用逗号分隔。类型参数约束立即生效,即编译错误阻止程序员犯错。考虑下面的DataBag约束。

public class DataBag where T : class{    public void Add(T value)    {        // omitted for brevity...}
}

现在,如果我试图实例化DataBag,C#编译器会让我知道我做错了什么。更具体地说,它要求类型 'DateTime' 必须是一个引用类型,以便将其作为 'T' 参数用于泛型类型或 'Program.DataBag' 方法中。

C# 3.0

下面是C#3.0的主要特性列表。

  • 匿名类型

  • 自动实现的属性

  • 表达树

  • 扩展方法

  • Lambda表达

  • 查询表达式

我徘徊于选择 Lambda表达式 还是 扩展方法 。但是,联系我目前的 C# 编程,相对于任何其他的 C# 运算符,我更多地使用lambda 操作符。我无法表达对它的喜爱。
在C#中有很多机会来利用 lambda 表达式和 lambda 运算符。=> lambda 运算符用于将左侧的输入与右侧的 lambda 表达式体隔离开来。

一些开发人员喜欢将 lambda 表达式看作是表达委托调用的一种较为冗长的方式。Action、Func 类型只是 System 名称空间中的预定义的一般委托。

让我们从解决一个假设的问题开始,使用 lambda 表达式来帮助我们编写一些富有表现力和简洁的 C# 代码。

想象一下,我们有大量代表趋势天气信息的记录。我们可能希望对这些数据执行一些操作,不是在一个典型的循环中遍历它,而是在某个时候,我们可以采用不同的方式。

public class WeatherData{    public DateTime TimeStampUtc { get; set; }    public decimal Temperature { get; set; }
} 
private IEnumerable GetWeatherByZipCode(string zipCode) { /* ... */ }

由于 GetWeatherByZipCode 的调用返回一个 IEnumerable,它可能看起来想让你循环迭代。假设我们有一个方法来计算平均温度。

private static decimal CalculateAverageTemperature(IEnumerable weather, DateTime startUtc, DateTime endUtc){    var sumTemp = 0m;    var total = 0;    foreach (var weatherData in weather){        if (weatherData.TimeStampUtc > startUtc &&weatherData.TimeStampUtc < endUtc){++ total;sumTemp += weatherData.Temperature;}}    return sumTemp / total;
}

我们声明一些局部变量来存储所有过滤日期范围内的温度总和及其总和,以便稍后计算平均值。在迭代内是一个 if 逻辑块,用于检查天气数据是否在特定的日期范围内。可以重写如下:

private static decimal CalculateAverageTempatureLambda(IEnumerable weather,DateTime startUtc,DateTime endUtc){    return weather.Where(w => w.TimeStampUtc > startUtc &&w.TimeStampUtc  w.Temperature).Average();
}

正如你所看到的那样,极大地简化了代码。if 逻辑块实际上只是一个谓词,如果天气日期在范围内,我们将继续进行一些额外的处理 - 就像一个过滤器。然后就像调用 Average 一样,当我们需要合计温度时,我们只需要投射 (或选择) IEnumerable 的温度过滤列表。

在 IEnumerable 接口上的 Where 和 Select 扩展方法中,使用 lambd a 表达式作为参数。Where 方法需要一个 Func

C# 4.0

相比之前的版本,C# 4.0 新增的主要特性较少。

  • 动态绑定

  • 嵌入式互操作类型

  • 泛型中的协变和逆变

  • 命名/可选参数

所有这些特性都是非常有用的。但是对于我来说,更倾向于命名可选参数,而不是泛型中的协变和逆变。这两者的取舍,取决于哪个是我最常用的,以及近年来最令 C# 开发人员受益的那个特性。

命名可选参数实至名归,尽管这是一个非常简单的特性,其实用性却很高。我就想问,谁没有写过重载或者带有可选参数的方法?

当您编写可选参数时,您必须为其提供一个默认值。如果你的参数是一个值类型,那么它必须是一个文字或者常数值,或者你可以使用 default 关键字。同样,您可以将值类型声明为 Nullable ,并将其赋值为 null 。假设我们有一个带有 GetData 方法的仓储。

public class Repository{   
 public DataTable GetData(string storedProcedure,DateTime start = default(DateTime),DateTime? end = null,      
  int? rows = 50,  
       int? offSet = null){        // omitted for brevity...        } }

正如我们所看到的,这个方法的参数列表相当长 - 好在有好几个可选参数。因此,调用者可以忽略它们,并使用默认值。正如你声明的那样,我们可以通过只传递 storedProcedure 参数来调用它。

var repo = new Repository();var sales = repo.GetData("sp_GetHistoricalSales");

现在我们已经熟悉了可选参数特性以及这些特性如何工作,顺便使用一下命名参数。以上面的示例为例,假设我们只希望我们的数据表返回 100 行而不是默认的 50 行。我们可以将我们的调用改为包含一个命名参数,并传递所需的重写值。

var repo = new Repository();var sales = repo.GetData("sp_GetHistoricalSales", rows: 100);

C# 5.0

像C#4.0版本一样,C#5.0版本中没有太多特性 - 但是其中有一个特性非常强大。

  • 异步/等待

  • 调用方信息

当 C# 5.0 发布时,它实际上改变了 C# 开发人员编写异步代码的方式。今天仍然有很多困惑,我在这里向您保证,这比大多数人想象的要简单得多。这是 C# 的一个重大飞跃 - 它引入了一个语言级别的异步模型,它极大地赋予了开发人员编写外观和感觉同步 (或者至少是连续的) 的“异步”代码。

异步编程在处理 I/O 相关(如与数据库、网络、文件系统等进行交互)时非常强大。异步编程通过使用非阻塞方法帮助处理吞吐量。这种机制在透明的异步状态机中代以使用暂停点和相应的延续的方式。

同样,如果 CPU 负载计算的工作量很大,则可能需要考虑异步执行此项工作。这将有助于用户体验,因为UI线程不会被阻塞,而是可以自由地响应其他UI交互。

***编者注:关于 C# 异步编程中使用异步等待的最佳实践,http://www.dotnetcurry.com/csharp/1307/async-await-asynchronous-programming-examples。***

在 C# 5.0 中,当语言添加了两个新的关键字async和await时,异步编程被简化了。这些关键字适用于 Task 和 Task 类型。下表将作为参考:

Task 和 Task 类型表示异步操作。这些操作既可以通过返回一个 Task ,也可以返回void Task。当您使用 async 关键字修改返回方法时,它将使方法主体能够使用await 关键字。在评估 await 关键字时,控制流将返回给调用者,并在该方法中的那一点暂停执行。当等待的操作完成时,会同时恢复执行。

class IOBoundAsyncExample{    // Yes, this is the internet Chuck Norris Database of jokes!private const string Url = "http://api.icndb.com/jokes/random?limitTo=[nerdy]"; internal async Task GetJokeAsync()    {     
   using (var client = new HttpClient()){          
     var response = await client.GetStringAsync(Url);    
             var result = JsonConvert.DeserializeObject(response); return result.Value.Joke;}} }public class Result{[JsonProperty("type")] public string Type { get; set; }[JsonProperty("value")] public Value Value { get; set; } } public class Value{[JsonProperty("id")] public int Id { get; set; }[JsonProperty("joke")] public string Joke { get; set; } }

我们用一个名为 GetJokeAsync 的方法定义一个简单的类,当我们调用方法时,该方法返回一个 Task 。对于调用者,GetJokeAsync 方法最终会给你一个字符串 - 或可能出错。

当响应返回时,从被暂停的地方恢复延续执行。然后,将结果 JSON 反序列化到 Result类的实例中,并返回 Joke 属性。

C# 6.0

C# 6.0 有很多很不错的改进,很难选择我最喜欢的特性。

  • 字典初始化

  • 异常过滤器

  • 表达式体成员

  • nameof 操作符

  • 空合并运算符

  • 属性初始化

  • 静态引用

  • 字符串插值

我把范围缩小到三个突出的特性:字符串插值,空合并运算符和 nameof 操作符。

尽管 nameof 操作符很棒,而且我经常用,但是显然另外两个特性更具影响力。又是一个两难的选择,最终还是字符串插值获胜出。

空合并运算符很有用,它能让我少写代码,但不一定防止我的代码中的错误。而使用字符串插值时,可以防止运行时出错。

使用 $ 符号插入字符串文字时,将启用 C# 中的字符串插值语法。相当于告诉 C# 编译器,我们要用到各种 C# 变量、逻辑或表达式来插入到此字符串。这对于手动拼接字符串、甚至是 string.Format 方法来说是一个重要的升级。先看一看如下代码:

class Person{    public string FirstName { get; set; }    public string LastName { get; set; } public override string ToString()        => string.Format("{0} {1}", FirstName);
}

我们有一个简单的 Person 类,具有两个属性,表示名字和姓氏。我们使用 string.Format 重写 ToString 方法。问题是,编译时,开发人员在希望将姓氏也作为结果字符串的一部分时,使用 “{0} {1} ”参数很容易出错。如上述代码中,他们忘了加姓氏。同样,开发人员可以很容易地交换参数位置,在混乱的格式文字只传递了第一个索引,等等...现在考虑用字符串插值实现。

class Person{    public string FirstName { get; set; } = "David";    public string LastName { get; set; } = "Pine";    public DateTime DateOfBirth { get; set; } = new DateTime(1984, 7, 7); public override string ToString()        => $"{FirstName} {LastName} (Born {DateOfBirth:MMMM dd, yyyy})";
}

我冒昧添加 DateOfBirth 属性和一些默认的属性值。另外,我们现在使用字符串插值重写 ToString 方法。作为一名开发人员,犯上述错误要困难得多。最后,我也可以在插值表达式中进行格式化。注意第三次插值,DateOfBirth 是 DateTime 类型 - 因此我们可以使用习惯的所有标准格式。只需使用 :运算符来分隔变量和格式化。

示例输出:

  • David Pine (Born July 7, 1984)

***编者注:有关C#6.0新特性的详细内容,请阅读 http://www.dotnetcurry.com/csharp/1042/csharp-6-new-features***

C# 7.0

  • 表达式体成员

  • 局部方法

  • Out 变量

  • 模式匹配

  • 局部引用和引用返回

  • 元组和解构

模式匹配、元组和 Out 变量之间,我选择了 Out 变量。
模式匹配是伟大的,但我真的不觉得自己经常使用它,至少现在还没有。也许我会在将来更多地使用它,但是到目前为止我所写的所有 C# 代码中,没有太多的地方可以运用。再次,这是一个了不起的特性,只不过不是我最喜欢的 C# 7.0 特性。

元组也是一个很好的改进,是服务于语言的这一重要部分,能成为一等公民真是值得庆祝。逃离了 .Item1,.Item2,.Item3等...的日子,但这么说不够准确,在反序列化中无法还原元组名称使这个公共 API 不太有用。

我同时不喜欢可变的 ValueTuple 类型。不明白这是谁设计的,希望有人能向我解释,感觉就像是一个疏忽。因此,只有 Out 变量合我心意。

从 C# 版本1.0以来,try-parse 模式已经在各种值类型中出现了。模式如下:

public boolean TryParse(string value, out DateTime date){    // omitted for brevity...}

该函数返回一个布尔值,指示给定的字符串值是否能够被解析。如果为 true,则将解析后的值分配给 data参数。它使用方式如下:

if (DateTime.TryParse(someDateString, out var date))
{    // date is now the parsed value}else{    // date is DateTime.MinValue, the default value}

这种模式尽管有用的,却有点麻烦。有时开发人员采取相同的模式,无论解析是否成功。有时可以使用默认值。C# 7.0中的 out变量使得这个更加复杂,尽管我不觉得复杂。

if (DateTime.TryParse(someDateString, out var date))
{    // date is now the parsed value}else{    // date is DateTime.MinValue, the default value}

现在我们移除了 if 语句块的外部声明,并把声明作为参数本身的一部分。使用 var 是合法的,因为类型是已知的。最后,date 变量的范围没有改变。它在声明中内联回 if 语句块之前。

你可能会问:“为什么这是我最喜欢的功能之一?”......这种看起来真的没有什么变化。

不要怀疑,它使我们的 C# 代码更具有表现力。每个人都喜欢扩展方法吧,那么请思考以下代码:

public static class StringExtensions{   

 private delegate bool TryParseDelegate(string s, out T result);
  private static T To(string value, TryParseDelegate parse)        => parse(value, out T result) ? result : default;
   public static int ToInt32(this string value)        => To(value, int.TryParse);
   public static DateTime ToDateTime(this string value)        => To(value, DateTime.TryParse);
   public static IPAddress ToIPAddress(this string value)        => To(value, IPAddress.TryParse);
   public static TimeSpan ToTimeSpan(this string value)        => To(value, TimeSpan.TryParse); }

这个扩展方法类看起来简洁、明确、强有力。在定义了一个遵循 try-parse 模式的私有委托之后,我们可以编写一个泛型复合方法,它可以传递泛型类型参数、字符串和 tryparse 泛型委托。现在我们可以放心地使用这些扩展方法,用法如下:

public class Program{    
public static void Main(string[] args)    {      
 var str =            string.Join(                "",                new[] { "James", "Bond", " +7 " }.Select(s => s.ToInt32()));Console.WriteLine(str); // prints "007"} }

***编辑注意:要了解C#7的所有新功能,请查看教程 http://www.dotnetcurry.com/csharp/1286/csharp-7-new-expected-features***

结论

这篇文章对我个人而言颇具挑战性。C# 的许多特性受我喜欢,因此在每个版本选出一个最喜欢的特性是非常困难的。

每个 C# 版本都包含了强大而有影响力的特性。C# 语言团队以无数的方式进行创新 - 其中之一就是迭代发布。在撰写本文时,C#7.1 和 7.2已正式发布。作为 C# 开发人员,我们正在生活在令人激动人心的语言进化时代!

排列出所有特性对我来说是非常有指示,有助于揭示哪些是实际有用的,哪些对我日常影响最大。我会一如既往的努力,成为务实的开发者!并非每一种特性对于手头的工作来说都是必要的,但了解什么是可用的是很有必要的。

当我们期待 C# 8 的提议和原型时,我对 C# 的未来感到兴奋,它正满怀信心、积极地试图减轻 “十亿美元的错误” (译者注: 图灵奖得主 Tony Hoare 曾指出空引用将造成十亿美元损失)

引用

  • https://docs.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-version-history

  • https://en.wikipedia.org/wiki/C_Sharp_(programming_language)

  • https://en.wikipedia.org/wiki/SOLID_(object-oriented_design)

  • https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/compiler-options/langversion-compiler-option

  • https://www.wintellect.com/clr-via-c-by-jeffrey-richter/


原文地址:https://www.cnblogs.com/chenug/p/8324786.html


.NET社区新闻,深度好文,欢迎访问公众号文章汇总 http://www.csharpkit.com

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

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

相关文章

Sentinel(十三)之动态规则扩展

转载自 动态规则扩展 规则 Sentinel 的理念是开发者只需要关注资源的定义&#xff0c;当资源定义成功后可以动态增加各种流控降级规则。Sentinel 提供两种方式修改规则&#xff1a; 通过 API 直接修改 (loadRules)通过 DataSource 适配不同数据源修改 手动通过 API 修改比较…

AspectCore动态代理中的拦截器详解(一)

前言在上一篇文章使用AspectCore动态代理中&#xff0c;简单说明了AspectCore.DynamicProxy的使用方式&#xff0c;由于介绍的比较浅显&#xff0c;也有不少同学留言询问拦截器的配置&#xff0c;那么在这篇文章中&#xff0c;我们来详细看一下AspectCore中的拦截器使用。两种配…

Actor-ES框架:Ray

并发1. 并发和并行并发&#xff1a;两个或多个任务在同一时间段内运行。关注点在任务分割。并行&#xff1a;两个或多个任务在同一时刻同时运行。关注点在同时执行。本文大多数情况下不会严格区分这两个概念&#xff0c;默认并发就是指并行机制下的并发。2. 好处随着多核处理器…

Sentinel(十五)之在生产环境中使用 Sentinel

转载自 在生产环境中使用 Sentinel 引言 Sentinel 目前已可用于生产环境&#xff0c;除了阿里巴巴以外&#xff0c;也有很多企业在生产环境中广泛使用 Sentinel。 生产环境的 Sentinel Dashboard 需要具备下面几个特性: 规则管理及推送&#xff0c;集中管理和推送规则。se…

Entity Framework Core 懒加载

众所周知在EF 6 及以前的版本中&#xff0c;是支持懒加载&#xff08;Lazy Loading&#xff09;的&#xff0c;可惜在EF Core 并不支持&#xff0c;必须使用Include方法来支持导航属性的数据加载。不过现在EF Core的开发团队打算恢复对这一功能的支持&#xff08;目前还未发布&…

Sentinel(十六)之AHAS Sentinel 控制台

转载自 AHAS Sentinel 控制台 AHAS Sentinel 是 Sentinel 的阿里云上版本&#xff0c;提供企业级的高可用防护服务&#xff0c;包括&#xff1a; 可靠的实时监控和历史秒级监控数据查询&#xff0c;包含 QPS、RT、load、CPU 使用率等指标&#xff0c;支持按照调用类型分类&a…

和各路巨佬の随机挑战3总结

第三次挑战\huge \texttt{\color{purple}第\color{blue}三\color{green}次\color{block}挑\color{red}战}第三次挑战 规则 随机挑取一蓝一紫一黑来做&#xff0c;拥有两次换题机会&#xff0c;若黑题是暂未学过的算法可以拥有无限次换题机会。 van♂van♂van♂成记录 过程 晚…

浅析Entity Framework Core2.0的日志记录与动态查询条件

一、 Entity Framework Core2.0的日志记录早在Entity Framework Core1.0 ,我们就使用相关的ILoggerProvider ILogger 这些基础接口类.来实现过日志记录.在Entity Framework Core2.0 估计是为了配合ASP.NET Core的日志.所以对这些接口进行了更进一步的包装,也弃用了一些接口和类…

Actor-ES框架:Ray--事件(Event)编写说明

Event作用&#xff1a;存储事件数据。IEventBaseK&#xff1a;是Actor的StateId的类型&#xff0c;可以是long、可以是string&#xff0c;Ray一般使用OGuid生成的字符串作为主键。编写Event继承IEventBase接口&#xff0c;Base部分如下&#xff1a; public string Id {…

设计模式之策略模式在地铁票价系统中的应用

引言设计模式是面向对象编程的一个非常精彩的部分。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性&#xff0c;它能帮助我们将应用组织成容易了解&#xff0c;容易维护&#xff0c;具有弹性的架构。本文通过一个简单的案例来讲述策略模式在地铁票价系…

Sentinel(十九)之主流框架的适配

转载自 主流框架的适配 注&#xff1a;适配模块仅提供相应适配功能&#xff0c;若希望接入 Sentinel 控制台&#xff0c;请务必参考 Sentinel 控制台文档。 云原生微服务体系 Spring Cloud Spring Cloud Alibaba 致力于提供微服务开发的一站式解决方案。Sentinel 与 Spring …

利用OCR文字识别+百度算法搜索,玩转冲顶大会、百万英雄、芝士超人等答题赢奖金游戏

【先上一张效果图】&#xff1a;一、原理&#xff1a;其实原理很简单&#xff1a;1.手机投屏到电脑&#xff1b;2.截取投屏画面的题目部分&#xff0c;进行识别&#xff0c;得到题目和三个答案&#xff1b;3.将答案按照一定的算法&#xff0c;进行搜索&#xff0c;得出推荐答案…

Sentinel(二十)之Envoy RLS Token Server

转载自 Envoy RLS Token Server Sentinel 提供了一个 Envoy Global Rate Limiting gRPC Service 的实现 sentinel-cluster-server-envoy-rls&#xff0c;借助集群限流 token server 来为 Envoy 服务网格提供集群流量控制的能力。 Note: You can refer to here for the Englis…

g4e基础篇#5 创建分支和保存代码

使用版本控制系统最常见的工作流程就是修改代码&#xff0c;保存代码&#xff0c;共享代码。Git提供了一个简单的3步工作流&#xff0c;让你方便的完成这些操作。1. 新建工作分支2. 提交更改3. 推送分支到中心存储库与团队成员共享Git 工作流按照以上3步操作&#xff0c;我们就…

P3952-时间复杂度【模拟】

正题 题目链接:https://www.luogu.org/problemnew/show/P3952 题目大意 比较复杂就直接给截图了 解题思路 开一个栈来维护序列&#xff0c;因为它保证合法的程序中一个变量不会相互嵌套所以就拿变量的字母当做每个循环的下标即可。然后对于输入的x,yx,yx,y有五种情况 xN,yN…

一步步部署基于Windows系统的Jenkins持续集成环境

如题&#xff1a;本文将介绍如何在Windows环境下运用Jenkins部署持续集成环境。之所以写本文&#xff0c;是因为在最近工作当中&#xff0c;学习使用Jenkins时&#xff0c;确实遇到了一些问题&#xff0c;而大多数教程文档都是基于Mac或是Linux平台。为此很是头疼&#xff0c;经…

Sentinel(二十二)之使用Nacos存储规则

转载自 Spring Cloud Alibaba基础教程&#xff1a;Sentinel使用Nacos存储规则 通过上一篇《使用Sentinel实现接口限流》的介绍&#xff0c;相信大家对Sentinel已经有了初步的认识。在Spring Cloud Alibaba的整合封装之下&#xff0c;接口限流这件事情可以非常轻易的整合到我们…

vue 开发2017年变化回顾及2018年展望

vue.js 变化从 github 的发布记录我们可以看到2017年 vue.js 的第一个发布为 v2.1.9&#xff0c;最后一个为 v2.5.13&#xff0c;主要发布小版本 2.2~2.5。这些发布提升了vue 与 TypeScript 的结合、改进了对服务端渲染&#xff08;SSR&#xff09;和 native 渲染的支持、提供了…

Sentinel(二十三)之使用Apollo存储规则

转载自 Spring Cloud Alibaba基础教程&#xff1a;Sentinel使用Apollo存储规则 上一篇我们介绍了如何通过Nacos的配置功能来存储限流规则。Apollo是国内用户非常多的配置中心&#xff0c;所以&#xff0c;今天我们继续说说Spring Cloud Alibaba Sentinel中如何将流控规则存储…

Quartz.Net分布式任务管理平台

前言&#xff1a;我相信大多数人公司的业务上都有定时任务这么个功能&#xff0c;我们公司也不例外&#xff0c;刚来公司的时候使用Quartz.Net为我们组做了第一个任务&#xff0c;大致流程是&#xff1a;新建一个控制台程序&#xff0c;引用需要的程序集&#xff0c;Execute方法…