上篇提到 Blazor 组件的高级写法,是采用扩展方法对 HTML 元素和组件进行扩展,以便于书写组件结构和代码阅读。本篇主要介绍扩展方法实现的思路。

  • 什么是扩展方法
  • 要扩展哪个类
  • 扩展方法的实现

1. 什么是扩展方法

若要对一个 C# 类型添加新方法,一是修改源码,二是派生类,三是扩展方法。前两者不是万能的,第一种我们不一定有源码,第二种类型不一定能继承,只有第三种是万能的方法,在项目中新建一个扩展类型即可对任何类型进行扩展。

一个扩展方法需要有如下条件:

  • 添加扩展类,类必须声明 static 修饰符
  • 添加方法,方法必须声明 static 修饰符
  • 方法第一个参数必须是扩展类型,且要有 this 关键字
//扩展类型
static class Extension
{
static void SayHello (this string name)
{
Console.WriteLine($"Hello, I'm {name}.");
}
} //测试
var name = "Known";
name.SayHello(); //输出
Hello, I'm Known.

2. 要扩展哪个类

上篇提到组件的高级写法,需要覆写组件的 BuildRenderTree 方法,这个方法有唯一类型参数 RenderTreeBuilder,对,就是这个类型,我们从它开始扩展一切 HTML 基本元素及自定义组件。

下面看看 RenderTreeBuilder 有哪些原生方法。

  • OpenElement,打开一个元素,呈现 <div> 等开始标签
  • CloseElement,关闭一个元素,呈现 </div> 等关闭标签
  • OpenComponent,打开一个组件,呈现 <MyComponent>
  • CloseComponent,关闭一个组件,呈现 </MyComponent>
  • AddAttribute,添加元素和组件的属性,有8个重载方法
  • AddMultipleAttributes,一次性添加多个属性,参数为字典类型
  • AddContent,添加标签内部的内容,有6个重载方法
  • AddMarkupContent,添加原始 HTML 字符内容
  • AddElementReferenceCapture,添加元素对象参考,通过它可获取元素对象的实例
  • AddComponentReferenceCapture,添加组件对象参考,通过它可获取组件对象的实例

掌握以上这些方法的使用后,我们就可以开发扩展我们需要的元素和组件。

3. 扩展方法的实现

由于 HTML 元素标签及其属性众多,为了方便且全面适配所有属性,增加一个属性建造者类型 AttributeBuilder 来管理元素属性。建造者类型如下:

public class AttributeBuilder
{
private readonly RenderTreeBuilder builder; public AttributeBuilder(RenderTreeBuilder builder)
{
this.builder = builder;
} public AttributeBuilder Add(string name, object value)
{
if (value != null)
builder.AddAttribute(1, name, value);
return this;
} public AttributeBuilder Id(string id) => Add("id", id);
public AttributeBuilder Name(string name) => Add("name", name);
...
}

添加一个 HTML 元素扩展类,用于扩展 HTML 元素,代码示例如下:

public static class HtmlExtension
{
//通用元素扩展方法
public static void Element(this RenderTreeBuilder builder, string name, Action<AttributeBuilder> child = null)
{
builder.OpenElement(0, name);
var attr = new AttributeBuilder(builder);
child?.Invoke(attr);
builder.CloseElement();
}
//div标签
public static void Div(this RenderTreeBuilder builder, Action<AttributeBuilder> child) => builder.Element("div", child);
...
}

下面写一个元素扩展方法的示例,并将呈现的 HTML 结构与 C# 代码进行比对,直观感受一下高级写法的妙处。

protected override void BuildRenderTree(RenderTreeBuilder builder)
{
builder.Div(attr => //<div id="myPanel" class="panel">
{ //
attr.Id("myPanel").Class("panel"); //
builder.Div(attr => // <div class="header">
{ //
attr.Class("header"); //
//这里构造 Panel 头部内容 //
}); // </div>
builder.Div(attr => // <div class="body">
{ //
attr.Class("body"); //
//这里构造 Panel 身体内容 //
}); // </div>
}); //</div>
}

再次优化一下扩展方法的示例,下面代码看起来是不是更整齐了一些。

protected override void BuildRenderTree(RenderTreeBuilder builder)
{
builder.Div("myPanel", "panel", attr => //<div id="myPanel" class="panel">
{ //
builder.Div("header", attr => // <div class="header">
{ //
//这里构造 Panel 头部内容 //
}); // </div>
builder.Div("body", attr => // <div class="body">
{ //
//这里构造 Panel 身体内容 //
}); // </div>
}); //</div>
}

再学Blazor——扩展方法的更多相关文章

  1. ASP.NET MVC学前篇之扩展方法、链式编程

    ASP.NET MVC学前篇之扩展方法.链式编程 前言 目的没有别的,就是介绍几点在ASP.NETMVC 用到C#语言特性,还有一些其他琐碎的知识点,强行的划分一个范围的话,只能说都跟MVC有关,有的 ...

  2. 一个利用扩展方法的实例:AttachDataExtensions

    扩展方法是C# 3.0(老赵对VB不熟)中最简单,也是最常用的语言特性之一.这是老赵自以为的一个简单却不失经典的实例: [AttributeUsage(AttributeTargets.All, Al ...

  3. 从扩展方法到匿名方法再到LINQ

    1.首先我们应该知道什么是扩展方法: 扩展方法使您能够向现有类型“添加”方法,而无需创建新的派生类型.重新编译或以其他方式修改原始类型. 扩展方法是一种特殊的静态方法,但可以像扩展类型上的实例方法一样 ...

  4. (转)再不用担心DataRow类型转换和空值了(使用扩展方法解决高频问题)

    再不用担心DataRow类型转换和空值了(使用扩展方法解决高频问题) XML文档操作集锦(C#篇) webapi文档描述-swagger

  5. 再谈扩展方法,从string.IsNullOrEmpty()说起

    string.IsNullOrEmpty()这个方法算得上是.net中使用频率最高的方法之一.此方法是string的一个静态方法,类似的静态方法在string这个类中还有很多.那么这样的方法作为静态方 ...

  6. 再不用担心DataRow类型转换和空值了(使用扩展方法解决高频问题)

    在使用DataRow读取数据时,通常会遇到数据可能为Null, 但是又需要转换为如int等其它类型的数据,因此就通常会写这样的代码: if (dr[name] != DBNull.Value & ...

  7. .NET 扩展方法 (一)

    我还记得刚刚学编程的时候,老师经常会提到一句话:注意空指针.所以经常在某些“入口”位置,进行代码校验,空指针的判断就是其中的一项工作. string类型作为常用的数据类型,它在项目中出现的机率极高,所 ...

  8. 【C】 01 - 再学C语言

    “C语言还用再学吗?嵌入式工程师可是每天都在用它,大家早就烂熟于心,脱离语言这个层面了”.这样说不无道理,这门古老的语言以其简单的语法.自由的形式的而著称.使用C完成工作并不会造成太大困扰,所以很少有 ...

  9. [C#详解] (1) 自动属性、初始化器、扩展方法

    文章来源:Slark.NET-博客园 http://www.cnblogs.com/slark/p/CSharp-focus-1.html 代码下载:点我下载 目录 前言 属性与自动属性 属性 自动属 ...

  10. C#——各种参数,扩展方法

    余近日复习C#之基础知识,故作一随笔,也是对此前几篇博客中所记录的传值参数相关内容之汇总,还望诸位加以批评指正. 该博客包括以下内容: 传值参数 引用参数 输出参数 数组参数 具名参数 可选参数 扩展 ...

随机推荐

  1. synchronized中wait、notify的原理与源码

    synchronized中wait.notify的原理与源码 1.wait和notify的流程图 2.JVM源码 java层面wait的方法 public final native void wait ...

  2. UI自动化 --- 微软UI Automation

    引言 自动化测试平台的意义就三个字 --- 稳定性. 无论是接口自动化测试,还是UI自动化测试,目的就是为了提高产品的稳定性,保证用户体验. 那常见的接口自动化测试比如有 Postman ,SoapU ...

  3. iota简介

    当声明枚举类型或定义一组相关常量时,Go语言中的iota关键字可以帮助我们简化代码并自动生成递增的值.本文档将详细介绍iota的用法和行为. iota关键字 iota是Go语言中的一个预定义标识符,它 ...

  4. 向量数据库Faiss的搭建与使用

    向量数据库Faiss是Facebook AI研究院开发的一种高效的相似性搜索和聚类的库.它能够快速处理大规模数据,并且支持在高维空间中进行相似性搜索.本文将介绍如何搭建Faiss环境并提供一个简单的使 ...

  5. ZEGO即构科技荣获36氪【WISE2020中国新经济之王最具影响力企业】

    12月8-10日,36氪重磅新经济峰会WISE2020新经济之王大会将在北京举办.近日,2020新经济之王--中国最具影响力企业榜单陆续发布,全球云通讯服务商即构科技,凭借在企业服务领域硬核出色的技术 ...

  6. Bug_ku source (WEB) wp

    在源代码中注释中发现了flag,提交发现是假的. 我们打开kali用dirserch扫描一下网站后台目录吧 发现.git ,这题应该是一个git泄露的题,用wget吧文件下载到本地,-r 选项的作用是 ...

  7. React报错:Module not found: Error: Can't resolve 'react-router-dom'

    解决方案 npm install -S react-router-dom@5 参考链接 https://stackoverflow.com/questions/53914013/failed-to-c ...

  8. TypeScript: 類型 'HTMLElement | null' 不可指派給類型 'HTMLElement'。 類型 'null' 不可指派給類型 'HTMLElement'

    报错截图 解决方案 在结尾添加叹号 // 获取页面中food的元素并将其赋值给element this.element = document.getElementById('food')!;

  9. .NET周刊【7月第5期 2023-07-30】

    国内文章 PaddleSharp:跨越一年的版本更新与亮点 https://www.cnblogs.com/sdflysha/p/20230724-paddlesharp-in-a-year.html ...

  10. 小白也能搞定!Windows10上CUDA9.0+CUDNN7.0.5的完美安装教程

    前言: 为什么要在本地电脑安装 CUDA,CUDA 是什么的,用来做什么?我想,点击标题进来的小伙伴,应该都清楚这些.不管你是用来做什么,或者跟我一样为了跑 Tensorflow 的 Object D ...