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

C# 简述委托,Func与Action委托。 他们之前有什么区别?

C#中的委托、FuncAction


1. 委托 (Delegate) - 基础概念

是什么?
委托是一个类型安全的函数指针,它定义了方法的签名(返回值类型和参数列表)。它允许你将方法作为参数传递,或者将方法存储在变量中,用于实现回调方法和事件处理。

核心思想: 后期绑定。让你能够在运行时决定要调用哪个方法。

如何声明?
使用 delegate 关键字。

// 1. 声明一个委托类型,它指向任何“接受一个string参数并返回void”的方法
public delegate void MyDelegate(string message);// 2. 定义一个符合签名的方法
public void MyMethod(string msg)
{Console.WriteLine("Message: " + msg);
}// 3. 使用
MyDelegate del = new MyDelegate(MyMethod); // 创建委托实例
del("Hello Delegate"); // 通过委托调用方法

2. Func 委托

是什么?
Func 是.NET框架提供的泛型内置委托。它代表一个有返回值的方法。

签名:
Func 有一系列重载,最多可以接受16个输入参数

  • Func<TResult> - 没有参数,返回 TResult 类型。
  • Func<T1, TResult> - 接受一个 T1 类型的参数,返回 TResult 类型。
  • Func<T1, T2, TResult> - 接受两个参数,返回 TResult 类型。
  • Func<T1, T2, ..., T16, TResult> - 接受16个参数,返回 TResult 类型。

最后一个泛型参数始终是返回值类型!

// 示例:一个接受两个int参数并返回一个int的方法
Func<int, int, int> add = (a, b) => a + b;
int result = add(5, 3); // result = 8// 示例:一个接受string参数并返回bool的方法
Func<string, bool> isLong = s => s.Length > 5;
bool longEnough = isLong("Hello World"); // longEnough = true

3. Action 委托

是什么?
Action 也是.NET框架提供的泛型内置委托。它代表一个没有返回值void)的方法。

签名:
Func 一样,Action 也有一系列重载,最多可以接受16个输入参数,但它没有返回值

  • Action - 没有参数,没有返回值。
  • Action<T1> - 接受一个 T1 类型的参数,没有返回值。
  • Action<T1, T2> - 接受两个参数,没有返回值。
  • Action<T1, T2, ..., T16> - 接受16个参数,没有返回值。
// 示例:一个接受一个string参数但没有返回值的方法
Action<string> log = message => Console.WriteLine($"Log: {message}");
log("Something happened!"); // 输出:Log: Something happened!// 示例:一个没有参数也没有返回值的方法
Action greet = () => Console.WriteLine("Hello!");
greet();

三者的区别总结

特性自定义 DelegateFunc 委托Action 委托
返回值必须明确声明必须有返回值必须没有返回值 (void)
声明方式需要使用 delegate 关键字自定义.NET 内置,无需自定义.NET 内置,无需自定义
便利性麻烦,需要先定义类型才能使用非常方便,直接使用非常方便,直接使用
用途早期C#版本,或需要更清晰语义时(如事件)代表有返回值的操作代表执行一个操作(无返回值)
参数自定义最后一个是返回类型,前面是输入参数所有泛型参数都是输入参数

使用场景与建议

  1. 自定义委托

    • 现在主要用于定义事件event关键字),因为事件需要明确的委托类型。
    • 当委托签名需要非常清晰的语义,并且会在代码中大量重复使用时(例如 EventHandler)。
  2. Func 委托

    • LINQ 查询中大量使用(例如 .Where(x => x > 5),这里的 lambda 表达式就是一个 Func<T, bool>)。
    • 任何需要传递或返回一个计算逻辑的场景。
  3. Action 委托

    • 用于执行一个操作。例如,启动一个新线程 Task.Run(() => { /* 做某些事 */ })
    • 执行回调方法,通知某件事已完成,但不需要返回结果。

简单类比

  • 自定义委托:像是自己动手打造一个专门的工具。
  • Func/Action:像是从工具箱里直接拿标准化的通用工具,省时省力。

现代C#开发中,除非必要(如事件),应优先使用 FuncAction,它们极大地减少了代码量,提高了开发效率。


通过一些实际开发中的复杂场景来深入理解委托、FuncAction的用法。

1. 回调机制与异步编程

使用 Action 作为完成回调

public class DataProcessor
{// 使用Action作为处理完成后的回调public void ProcessDataAsync(string data, Action<string> onCompleted, Action<Exception> onError = null){Task.Run(() =>{try{// 模拟耗时处理Thread.Sleep(1000);var result = data.ToUpper() + "_PROCESSED";// 在主线程执行回调(假设有同步上下文)onCompleted?.Invoke(result);}catch (Exception ex){onError?.Invoke(ex);}});}
}// 使用示例
var processor = new DataProcessor();
processor.ProcessDataAsync("hello world", result => Console.WriteLine($"处理结果: {result}"),error => Console.WriteLine($"错误: {error.Message}"));

使用 Func 进行重试机制

public static class RetryHelper
{public static TResult ExecuteWithRetry<TResult>(Func<TResult> operation, int maxRetries = 3, int delayMs = 1000){int attempts = 0;while (true){try{attempts++;return operation();}catch (Exception ex) when (attempts < maxRetries){Console.WriteLine($"尝试 {attempts} 失败,{delayMs}ms后重试。错误: {ex.Message}");Thread.Sleep(delayMs);}}}
}// 使用示例
var result = RetryHelper.ExecuteWithRetry(() =>
{// 模拟不可靠的操作(如网络请求、数据库操作)if (new Random().Next(0, 5) == 0) // 20% 失败率throw new Exception("操作失败");return DateTime.Now.ToString();
});Console.WriteLine($"最终结果: {result}");

2. 策略模式与动态算法选择

使用 Func 实现策略模式

public class PriceCalculator
{private readonly Func<decimal, decimal> _discountStrategy;// 通过构造函数注入策略public PriceCalculator(Func<decimal, decimal> discountStrategy){_discountStrategy = discountStrategy;}public decimal CalculateFinalPrice(decimal basePrice){return _discountStrategy(basePrice);}
}// 定义不同的策略
public static class DiscountStrategies
{public static decimal NoDiscount(decimal price) => price;public static decimal TenPercentDiscount(decimal price) => price * 0.9m;public static decimal SeasonalDiscount(decimal price) => price > 100 ? price - 20 : price;
}// 使用示例
var calculator = new PriceCalculator(DiscountStrategies.SeasonalDiscount);
var finalPrice = calculator.CalculateFinalPrice(150m);
Console.WriteLine($"最终价格: {finalPrice}");// 动态切换策略
calculator = new PriceCalculator(DiscountStrategies.TenPercentDiscount);
finalPrice = calculator.CalculateFinalPrice(150m);
Console.WriteLine($"折扣后价格: {finalPrice}");

3. 事件处理与观察者模式

自定义委托用于事件

public class OrderService
{// 使用自定义委托定义事件(更清晰语义)public delegate void OrderProcessedEventHandler(Order order, DateTime processedTime);public event OrderProcessedEventHandler OrderProcessed;// 使用Action定义简单事件public event Action<Order> OrderCreated;public void ProcessOrder(Order order){// 处理订单逻辑...Console.WriteLine($"处理订单: {order.Id}");// 触发事件OrderProcessed?.Invoke(order, DateTime.Now);OrderCreated?.Invoke(order);}
}// 使用示例
var orderService = new OrderService();// 订阅事件
orderService.OrderProcessed += (order, time) => Console.WriteLine($"订单 {order.Id}{time} 处理完成");orderService.OrderCreated += order =>Console.WriteLine($"新订单创建: {order.Id}");orderService.ProcessOrder(new Order { Id = "ORD001", Amount = 99.99m });

4. LINQ 扩展与复杂查询

使用 Func 创建动态查询

public static class QueryExtensions
{public static IEnumerable<T> WhereDynamic<T>(this IEnumerable<T> source, Func<T, bool> predicate = null,Func<T, bool> additionalCondition = null){var query = source;if (predicate != null)query = query.Where(predicate);if (additionalCondition != null)query = query.Where(additionalCondition);return query;}public static IEnumerable<TResult> SelectDynamic<T, TResult>(this IEnumerable<T> source,Func<T, TResult> selector){return source.Select(selector);}
}// 使用示例
var users = new List<User>
{new User { Name = "Alice", Age = 25, IsActive = true },new User { Name = "Bob", Age = 30, IsActive = false },new User { Name = "Charlie", Age = 35, IsActive = true }
};// 动态构建查询
var activeUsers = users.WhereDynamic(u => u.IsActive);
var activeUserNames = users.WhereDynamic(u => u.IsActive).SelectDynamic(u => u.Name);// 更复杂的条件组合
Func<User, bool> ageFilter = u => u.Age > 28;
Func<User, bool> nameFilter = u => u.Name.StartsWith("C");var filteredUsers = users.WhereDynamic(ageFilter, nameFilter);

5. 中间件管道模式

使用 Func 构建处理管道

public class ProcessingPipeline<T>
{private readonly List<Func<T, Func<T>, T>> _middlewares = new List<Func<T, Func<T>, T>>();public ProcessingPipeline<T> Use(Func<T, Func<T>, T> middleware){_middlewares.Add(middleware);return this;}public T Execute(T initialContext){Func<T> next = () => initialContext;// 反向构建中间件链for (int i = _middlewares.Count - 1; i >= 0; i--){var currentMiddleware = _middlewares[i];var nextCopy = next;next = () => currentMiddleware(initialContext, nextCopy);}return next();}
}// 使用示例
var pipeline = new ProcessingPipeline<string>().Use((context, next) => {Console.WriteLine($"Middleware 1 前: {context}");var result = next();Console.WriteLine($"Middleware 1 后: {result}");return result + "_processed1";}).Use((context, next) => {Console.WriteLine($"Middleware 2 前: {context}");var result = next();Console.WriteLine($"Middleware 2 后: {result}");return result.ToUpper();});var finalResult = pipeline.Execute("initial_data");
Console.WriteLine($"最终结果: {finalResult}");

6. 依赖注入与工厂模式

使用 Func 作为工厂委托

public interface ILogger
{void Log(string message);
}public class FileLogger : ILogger
{private readonly string _filePath;public FileLogger(string filePath) => _filePath = filePath;public void Log(string message) => File.AppendAllText(_filePath, message + Environment.NewLine);
}public class ConsoleLogger : ILogger
{public void Log(string message) => Console.WriteLine(message);
}public class LoggerFactory
{private readonly Func<string, ILogger> _fileLoggerFactory;private readonly Func<ILogger> _consoleLoggerFactory;public LoggerFactory(Func<string, ILogger> fileLoggerFactory, Func<ILogger> consoleLoggerFactory){_fileLoggerFactory = fileLoggerFactory;_consoleLoggerFactory = consoleLoggerFactory;}public ILogger CreateFileLogger(string path) => _fileLoggerFactory(path);public ILogger CreateConsoleLogger() => _consoleLoggerFactory();
}// 在依赖注入容器中注册(伪代码)
// services.AddSingleton<Func<string, ILogger>>(path => new FileLogger(path));
// services.AddSingleton<Func<ILogger>>(() => new ConsoleLogger());
// services.AddSingleton<LoggerFactory>();

关键总结

  1. 自定义委托:主要用于事件和需要明确语义的场合
  2. Action:用于执行操作,无返回值,适合回调、事件简化版
  3. Func:用于计算和转换,有返回值,适合策略模式、工厂方法、LINQ扩展

在实际复杂开发中,这些委托类型让代码更加灵活、可扩展和可测试,是实现许多设计模式的关键工具。


文章转载自:

http://1drHwE9k.bppmL.cn
http://GAr5efkN.bppmL.cn
http://WTqKkGoC.bppmL.cn
http://ToS2awdW.bppmL.cn
http://Yyckg5C9.bppmL.cn
http://iXOiJBzj.bppmL.cn
http://hdEf9jDX.bppmL.cn
http://lCgtMzzX.bppmL.cn
http://u6AjCWy8.bppmL.cn
http://BffNDLis.bppmL.cn
http://jvBH4ttO.bppmL.cn
http://ZyKIagrj.bppmL.cn
http://GPRsDWAS.bppmL.cn
http://ymqArlPC.bppmL.cn
http://Y8PnsJ1C.bppmL.cn
http://dRgMCItf.bppmL.cn
http://1dHw6K6o.bppmL.cn
http://ohIf0MdQ.bppmL.cn
http://W8SEDBPS.bppmL.cn
http://uw6FQ9ho.bppmL.cn
http://PxdPwZyn.bppmL.cn
http://csssTTIW.bppmL.cn
http://s5HHaCIV.bppmL.cn
http://gNtyvbM6.bppmL.cn
http://DTQz8O4a.bppmL.cn
http://uJqPT7GR.bppmL.cn
http://JiXfRE5R.bppmL.cn
http://j3YM655G.bppmL.cn
http://Xb07UClp.bppmL.cn
http://tfuVlxXO.bppmL.cn
http://www.dtcms.com/a/363172.html

相关文章:

  • MCU上跑AI—实时目标检测算法探索
  • 将css中的线性渐变,径向渐变,锥心渐变,转成canvas中的渐变
  • 【高并发内存池】三、线程缓存的设计
  • SpringBoot3中使用Caffeine缓存组件
  • Ruoyi-vue-plus-5.x第三篇Redis缓存与分布式技术:3.2 缓存注解与使用
  • 悬停头部的实现方式之一 css: position: sticky
  • SQL Server-查询事务日志
  • 血缘元数据采集开放标准:OpenLineage Guides 在 Spark 中使用 OpenLineage
  • B2B营销面临的一些主要问题
  • 3025. 人员站位的方案数 I
  • HDI线路板与普通板有何区别?厂家生产难度在哪?
  • 【leetcode】236. 二叉树的最近公共祖先
  • 《“人工智能+”行动意见》深度解析:从智能红利到产业落地,直播SDK的技术价值与应用路径
  • Kafka:Java开发的消息神器,你真的懂了吗?
  • 货运系统源码 货运物流小程序 货运平台搭建 货运软件开发
  • 深度学习——基于卷积神经网络实现食物图像分类【4】(使用最优模型)
  • Directus搜索功能:全文检索和高级过滤的技术实现
  • LeetCode22生成括号算法
  • 【开题答辩全过程】以 基于PHP的蔬菜食杂购物系统为例,包含答辩的问题和答案
  • 完全背包|dfs
  • qt安装FFmpeg后编译遇到error: collect2.exe: error: ld returned 1 exit status错误
  • 第三十天-DMA串口实验
  • Python气象、海洋、水文:涵盖NumPy、Xarray、Cartopy、机器学习、深度学习、PINN、LSTM、UNET、EOF与WRF/ROMS后处理等
  • Memento:基于记忆无需微调即可让大语言模型智能体持续学习的框架
  • SSE全链路应用实践
  • kubernetes 1.31 节点之间(1个master ,多个worker)使用了哪些端口及防火墙设置
  • 软件测试面试题【内附超详细面试宝典】
  • @Apache Hive 介绍部署与使用详细指南
  • ProfiNet 转 Ethernet/IP 协议转换实践:企业电池模组智能产线升级案例
  • WAF与CDN在网络安全中的协同作用