当前位置: 首页 > article >正文

windows C#-扩展方式的常见使用模式

集合功能

过去,创建”集合类”通常是为了使给定类型实现 System.Collections.Generic.IEnumerable<T> 接口,并实现对该类型集合的功能。 创建这种类型的集合对象没有任何问题,但也可以通过对 System.Collections.Generic.IEnumerable<T> 使用扩展来实现相同的功能。 扩展的优势是允许从任何集合(如 System.Array 或实现该类型 System.Collections.Generic.IEnumerable<T> 的 System.Collections.Generic.List<T>)调用功能。 可以在本文前面的内容中找到使用 Int32 的数组的示例。

特定于层的功能

使用洋葱架构或其他分层应用程序设计时,通常具有一组域实体或数据传输对象,可用于跨应用程序边界进行通信。 这些对象通常不包含任何功能,或者只包含适用于应用程序的所有层的最少功能。 使用扩展方法可以添加特定于每个应用程序层的功能,而无需使用其他层中不需要的方法来向下加载对象。

public class DomainEntity
{
    public int Id { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

static class DomainEntityExtensions
{
    static string FullName(this DomainEntity value)
        => $"{value.FirstName} {value.LastName}";
}
扩展预定义类型

当需要创建可重用功能时,我们无需创建新对象,而是可以扩展现有类型,例如 .NET 或 CLR 类型。 例如,如果不使用扩展方法,我们可能会创建 Engine 或 Query 类,对可从代码中的多个位置调用的 SQL Server 执行查询。 但是,如果换做使用扩展方法扩展 System.Data.SqlClient.SqlConnection 类,就可以从与 SQL Server 连接的任何位置执行该查询。 其他示例可能是向 System.String 类添加常见功能、扩展 System.IO.Stream 和 System.Exception 对象的数据处理功能以实现特定的错误处理功能。 这些用例的类型仅受想象力和判断力的限制。

使用 struct 类型扩展预定义类型可能很困难,因为它们已通过值传递给方法。 这意味着将对结构的副本进行任何结构更改。 扩展方法退出后,将不显示这些更改。 可以将 ref 修饰符添加到第一个参数,使其成为 ref 扩展方法。 ref 关键字可以在 this 关键字之前或之后显示,不会有任何语义差异。 添加 ref 修饰符表示第一个参数是按引用传递的。 在这种情况下,可以编写扩展方法来更改要扩展的结构的状态(请注意,私有成员不可访问)。 仅允许值类型或受结构约束的泛型类型作为 ref 扩展方法的第一个参数。 以下示例演示如何使用 ref 扩展方法直接修改内置类型,而无需重新分配结果或使用 ref 关键字传递函数:

public static class IntExtensions
{
    public static void Increment(this int number)
        => number++;

    // Take note of the extra ref keyword here
    public static void RefIncrement(this ref int number)
        => number++;
}

public static class IntProgram
{
    public static void Test()
    {
        int x = 1;

        // Takes x by value leading to the extension method
        // Increment modifying its own copy, leaving x unchanged
        x.Increment();
        Console.WriteLine($"x is now {x}"); // x is now 1

        // Takes x by reference leading to the extension method
        // RefIncrement changing the value of x directly
        x.RefIncrement();
        Console.WriteLine($"x is now {x}"); // x is now 2
    }
}

下一个示例演示用户定义的结构类型的 ref 扩展方法:

public struct Account
{
    public uint id;
    public float balance;

    private int secret;
}

public static class AccountExtensions
{
    // ref keyword can also appear before the this keyword
    public static void Deposit(ref this Account account, float amount)
    {
        account.balance += amount;

        // The following line results in an error as an extension
        // method is not allowed to access private members
        // account.secret = 1; // CS0122
    }
}

public static class AccountProgram
{
    public static void Test()
    {
        Account account = new()
        {
            id = 1,
            balance = 100f
        };

        Console.WriteLine($"I have ${account.balance}"); // I have $100

        account.Deposit(50f);
        Console.WriteLine($"I have ${account.balance}"); // I have $150
    }
}

 通用准则

尽管通过修改对象的代码来添加功能,或者在合理和可行的情况下派生新类型等方式仍是可取的,但扩展方法已成为在整个 .NET 生态系统中创建可重用功能的关键选项。 对于原始源不受控制、派生对象不合适或不可用,或者不应在功能适用范围之外公开功能的情况,扩展方法是一个不错的选择。

在使用扩展方法来扩展你无法控制其源代码的类型时,你需要承受该类型实现中的更改会导致扩展方法失效的风险。

如果确实为给定类型实现了扩展方法,请记住以下几点:

  • 如果扩展方法与该类型中定义的方法具有相同的签名,则扩展方法永远不会被调用。
  • 在命名空间级别将扩展方法置于范围中。 例如,如果你在一个名为 Extensions 的命名空间中具有多个包含扩展方法的静态类,则这些扩展方法将全部由 using Extensions; 指令置于范围中。

针对已实现的类库,不应为了避免程序集的版本号递增而使用扩展方法。 如果要向你拥有源代码的库中添加重要功能,请遵循适用于程序集版本控制的 .NET 准则。 


http://www.kler.cn/a/441265.html

相关文章:

  • 【性能优化专题系列】利用CompletableFuture优化多接口调用场景下的性能
  • 【单细胞第二节:单细胞示例数据分析-GSE218208】
  • [论文总结] 深度学习在农业领域应用论文笔记14
  • 春晚舞台上的人形机器人:科技与文化的奇妙融合
  • 登录授权流程
  • 基于Langchain-Chatchat + ChatGLM 本地部署知识库
  • Visual Studio 2022 安装和管理 GitHub Copilot
  • 【计算机网络】期末考试预习复习|中
  • 前端(组件间传参)
  • 柚坛工具箱Uotan Toolbox适配鸿蒙,刷机体验再升级
  • sylar:日志管理
  • 力扣hot100——子串
  • Spark3.2.0集群部署ON YARN
  • Electron-Vue 框架的构成拆解 动态 Webpcak 5 打包
  • 2024三掌柜赠书活动第三十六期:深度学习高手笔记系列
  • ChatGPT Search开放:实时多模态搜索新体验
  • [OpenGL] 崩溃在nvoglv32.dll
  • LeetCode:239. 滑动窗口最大值
  • 【功能安全】软件安全架构
  • Ubuntu批量修改文件名
  • Netty 常见面试题原理解析
  • Java-08
  • FFmpeg 4.3 音视频-多路H265监控录放C++开发二十一.2,RTP协议-RTP协议概述,协议详情
  • 国标GB28181网页直播平台EasyGBS国标EasyGBD对讲音频demo
  • 大语言模型推理技术知识体系
  • Leetcode1847:最近的房间