第三单元 扩展知识
扩展方法使你能够向现有类型“添加”方法,而无需创建新的派生类型、重新编译或以其他方式修改原始类型。 扩展方法是一种静态方法,但可以像扩展类型上的实例方法一样进行调用。 对于用 C#、F# 和 Visual Basic 编写的客户端代码,调用扩展方法与调用在类型中定义的方法没有明显区别。
最常见的扩展方法是 LINQ 标准查询运算符,它将查询功能添加到现有的
OrderBy 示例
下面的示例演示如何对一个整数数组调用标准查询运算符 OrderBy
方法。 括号里面的表达式是一个 lambda 表达式。 很多标准查询运算符采用 Lambda 表达式作为参数,但这不是扩展方法的必要条件。 有关详细信息,请参阅
class ExtensionMethods2 { static void Main() { int[] ints = { 10, 45, 15, 39, 21, 26 }; var result = ints.OrderBy(g => g); foreach (var i in result) { System.Console.Write(i + " "); } } } //Output: 10 15 21 26 39 45
扩展方法被定义为静态方法,但它们是通过实例方法语法进行调用的。 它们的第一个参数指定方法操作的类型。 参数前面是
自定义扩展方法
-
创建一个静态类
-
创建一个静态方法,这个方法即是你的扩展方法
-
方法中必须将你要扩展的类型通过参数传递进来
-
在你需要扩展的参数类型前面加this
namespace Utils; // 你的命名空间 // 扩展方法的工具类,注意一定要写成static 静态类 public static class ExtendUtils { /** * 1. 静态类下所有的方法都只能是static 方法 * 2. 把你需要扩展的类型前面加this */ public static int ParseInt(this string str) { if (string.IsNullOrWhiteSpace(str)) { return 0; } int result = 0; if (!int.TryParse(str, out result)) { return 0; } return result; }
使用
-
在你使用扩展方法之前,必须将扩展方法所在命名空间引用进来
using System; using NUnit.Framework; using Utils; // 若要使用扩展方法,必须先将其所在命名空间引用进来 namespace TestProject1; public class Tests { [SetUp] public void Setup() { } [Test] public void Test1() { string strNumber = "30"; Console.WriteLine(strNumber.ParseInt()); // 使用扩展方法 } }
2. 特性
使用特性,可以有效地将元数据或声明性信息与代码(程序集、类型、方法、属性等)相关联。 将特性与程序实体相关联后,可以在运行时使用反射这项技术查询特性,常运用于AOP技术。
特性具有以下属性:
-
特性向程序添加元数据。 元数据是程序中定义的类型的相关信息。 所有 .NET 程序集都包含一组指定的元数据,用于描述程序集中定义的类型和类型成员。 可以添加自定义特性来指定所需的其他任何信息。 有关详细信息,请参阅
-
可以将一个或多个特性应用于整个程序集、模块或较小的程序元素(如类和属性)。
-
特性可以像方法和属性一样接受自变量。
-
程序可使用反射来检查自己的元数据或其他程序中的元数据。 有关详细信息,请参阅
创建自定义特性
可通过定义特性类创建自己的自定义特性,特性类是直接或间接派生自
[System.AttributeUsage(System.AttributeTargets.Class | System.AttributeTargets.Struct) ] public class AuthorAttribute : System.Attribute { private string name; public double version; public AuthorAttribute(string name) { this.name = name; version = 1.0; } }
类名 AuthorAttribute
是该特性的名称,即 Author
加上 Attribute
后缀。 由于该类派生自 System.Attribute
,因此它是一个自定义特性类。 构造函数的参数是自定义特性的位置参数。 在此示例中,name
是位置参数。 所有公共读写字段或属性都是命名参数。 在本例中,version
是唯一的命名参数。 请注意,使用 AttributeUsage
特性可使 Author
特性仅对类和 struct
声明有效。
可按如下方式使用这一新特性:
[Author("P. Ackerman", version = 1.1)] class SampleClass { // P. Ackerman's code goes here... } AttributeUsage 有一个命名参数 AllowMultiple,通过此命名参数可一次或多次使用自定义特性。 下面的代码示例创建了一个多用特性。 [System.AttributeUsage(System.AttributeTargets.Class | System.AttributeTargets.Struct, AllowMultiple = true) // multiuse attribute ] public class AuthorAttribute : System.Attribute
在下面的代码示例中,某个类应用了同一类型的多个特性。
[Author("P. Ackerman", version = 1.1)] [Author("R. Koch", version = 1.2)] class SampleClass { // P. Ackerman's code goes here... // R. Koch's code goes here... }
3. JSON 操作
JSON: JavaScript Object Notation(JavaScript 对象表示法)
JSON 是存储和交换文本信息的语法,类似 XML。
JSON 比 XML 更小、更快,更易解析。
1. 什么是Json
-
SON 指的是 JavaScript 对象表示法(JavaScript Object Notation)
-
JSON 是轻量级的文本数据交换格式
-
JSON 独立于语言:JSON 使用 Javascript语法来描述数据对象,但是 JSON 仍然独立于语言和平台。JSON 解析器和 JSON 库支持许多不同的编程语言。 目前非常多的动态(PHP,JSP,.NET)编程语言都支持JSON。
-
JSON 具有自我描述性,更易理解
{ "sites": [ {id:1, "name":"C#教程" , "url":"www.runoob.com" }, {id:2, "name":"google" , "url":"www.google.com" }, {id:3, "name":"微博" , "url":"www.weibo.com" } ] }
大家平时在自己写JSON时,可以借助于
{ "sites": [ { "name": "菜鸟教程", "url": "www.runoob.com" }, { "name": "google", "url": "www.google.com" }, { "name": "微博", "url": "www.weibo.com" } ] }
JSON 语法规则
-
数据在键值对中
-
数据由逗号分隔
-
花括号保存对象
-
方括号保存数组
JSON 名称/值对
JSON 数据的书写格式是:名称/值对。
名称/值对组合中的名称写在前面(在双引号中),值对写在后面(同样在双引号中),中间
用冒号隔开:"firstName":"John"
JSON 值可以是:
数字(整数或浮点数)
字符串(在双引号中)
逻辑值(
true 或 false)
数组(在方括号中)
对象(在花括号中)
null
JSON数据结构
json简单说就是javascript中的对象和数组,所以这两种结构就是对象和数组两种结构,通
过这两种结构可以表示各种复杂的结构
1、对象:对象在js中表示为“{}”括起来的内容,数据结构为 {key:value,key:
value,...}的键值对的结构,在面向对象的语言中,key为对象的属性,value为对应的属性
值,所以很容易理解,取值方法为 对象.key (
c# 对象[key])获取属性值,这个属性值的
类型可以是 数字、字符串、数组、对象几种。
2、数组:数组在js中是中括号“[]”括起来的内容,数据结构为
["java","javascript","vb",...],取值方式和所有语言中一样,使用索引获取,字段值的
类型可以是 数字、字符串、数组、对象几种。
经过对象、数组2种结构就可以组合成复杂的数据结构了。
.Net 中提供的JSON解析组件
-
Newtonsoft.Json
-
fastjson
2. 序列化与反序列化
使用nuget 工具 将 Newtonsoft.Json
引用到当前项目中
序列化
对象转换为Json
using Newtonsoft.Json; public class Site { public int Id { get; set; } public string Name { get; set; } public string Url { get; set; } } // 对象转换为Json [Test] public void ObjectToJson() { Site site = new() { Id = 1, Name = "任我行网络教育有限公司", Url = "www.renwoxing.com" }; string json = JsonConvert.SerializeObject(site); Console.WriteLine(json); } // 输出结果 {"Id":1,"Name":"任我行网络教育有限公司","Url":"www.renwoxing.com"}
集合序列化
[Test] public void ListToJson() { List<Site> sites = new List<Site>(); sites.Add(new() { Id = 1, Name = "任我行网络教育有限公司", Url = "www.renwoxing.com" }); sites.Add(new() { Id = 2, Name = "百度", Url = "www.baidu.com" }); string json = JsonConvert.SerializeObject(sites); Console.WriteLine(json); }
输出结果:
[{ "Id": 1, "Name": "任我行网络教育有限公司", "Url": "www.renwoxing.com" }, { "Id": 2, "Name": "百度", "Url": "www.baidu.com" }]
反序列化
json转对象
[Test] public void JsonToObject() { string json = "{\"Id\":1,\"Name\":\"任我行网络教育有限公司\",\"Url\":\"www.renwoxing.com\"}"; Site site = JsonConvert.DeserializeObject<Site>(json); }
json转集合
[Test] public void JsonToList() { string json = "[{\"Id\": 1,\"Name\": \"任我行网络教育有限公司\",\"Url\": \"www.renwoxing.com\"},
{\"Id\": 2,\"Name\": \"百度\",\"Url\": \"www.baidu.com\"}]"; List<Site> sites = JsonConvert.DeserializeObject<List<Site>>(json); Console.WriteLine(sites.Count); }
4. 综合训练
结合反射,枚举,特性,扩展方法,完成综合练习。
-
声明枚举如下:
using System.ComponentModel; /** * 订单状态 */ public enum OrderStateEnum { [Description("待支付")] WaitPay, [Description("待发货")] WaitSend, [Description("待收货")] WaitReceive, [Description("待评论")] WaitComment, [Description("已完成")] Finish, [Description("取消订单")] Cancel }
-
要求 封装OrderStateEnum的扩展 方法 GetDescription() ,效果如下
string desc = OrderStateEnum.WaitPay.GetDescription(); Console.WriteLine(desc); // 输出:待支付
3. 具体实现
/// <summary> /// 获取描述特性信息 /// </summary> /// <param name="stateEnum"></param> /// <returns></returns> public static string GetDescription(this OrderStateEnum stateEnum) { var type = stateEnum.GetType(); var fieldInfo = type.GetField(stateEnum.ToString()); var desc = fieldInfo.GetCustomAttribute<DescriptionAttribute>(); return desc.Description; }
配套视频链接: