上篇提到 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. mysql where和having的用法例子

    结论:想在分组之后在进行过滤就要使用having了,如果只是对指定的行进行过滤的话,那么就需要使用where了

  2. 如何让一句话木马绕过waf ?

    一.什么是一句话木马? 一句话木马就是只需要一行代码的木马,短短一行代码,就能做到和大马相当的功能.为了绕过waf的检测,一句话木马出现了无数中变形,但本质是不变的:木马的函数执行了我们发送的命令. ...

  3. 完全兼容DynamoDB协议!GaussDB(for Cassandra)为NoSQL注入新活力

    摘要:DynamoDB是一款托管式的NoSQL数据库服务,支持多种数据模型,广泛应用于电商.社交媒体.游戏.IoT等场景. 本文分享自华为云社区<完全兼容DynamoDB协议!GaussDB(f ...

  4. 如何将Maven项目快速改造成一个java web项目(方式一)

    因为实际需要,需要将一个maven项目改造成原生的java-web项目,写这边博客 来记录整个改造的过程.原始的maven项目,使用IDEA打开后,目录结构如下所示 直接通过文件夹查看项目结果如下 首 ...

  5. ChatGPT帮助工程师写代码:从功能模块完善到成功执行,实现需求

    在软件开发过程中,经常会遇到需要完善功能模块.调试代码和解决问题的情况.为了提高效率,我们可以借助人工智能技术,例如OpenAI的ChatGPT语言模型,来协助我们进行代码编写和调试.本文将介绍一个案 ...

  6. idea连接数据库及使用

    连接数据库 idea本身足够强大,可以直接操作数据库. 1.打开idea后,点击右侧的Database,点击加号,点击Data Source,在右侧选择需要的数据库,我这里选择mysql. 2.填写完 ...

  7. EF命令行工具 migrate.exe 进行Code First更新数据库,6.3+使用ef6.exe

    EF命令行工具 migrate.exe 进行Code First更新数据库,6.3+使用ef6.exe 使用EF的Code First迁移可以用于从Visual Studio内部更新数据库,但也可通过 ...

  8. ansible 的特点

    ansible的特点 基于Python语言实现 模块化,调用特定的模块,完成特定任务 部署简单,基于python和SSH(默认已安装),yum install 即可,不需要客户端 安全,基于OpenS ...

  9. IRF技术介绍及配置介绍

    IRF技术介绍及配置介绍 IRF(Intelligent Resilient Framework,智能弹性架构)是 H3C 自主研发的软件虚拟化技术. 它的核心思想是将多台设备通过 IRF 物理端口连 ...

  10. Django: 'block' tag with name 'header' appears more than once

    错误原因 在同一文件中,重复引用标签多次 解决方案: 删掉重复的标签即可.