自从我开始了解扩展方法以来,我不断地发现新的可能性,让我的编码生活更轻松。 扩展方法是 SOLID完美应用 中的O ——开闭原则。 一个类应该尽可能简单,并且只在其他组件真正需要时才将属性和方法暴露给外部。
通过扩展方法,您可以为您的类实现额外的方法,而无需更改类本身! 这非常适合将类作为参数的重复方法。
实现扩展方法非常简单。 看看下面的例子:
namespace System;
public static class EnumerableExtensions
{
public static void ForEach(this IEnumerable sequence, Action action) {
foreach (var item in sequence)
action(item);
}
}
这在每个 IEnumerable
自 .NET 6 以来,Microsoft 为 IEnumerable
事不宜迟,以下是我在 .NET 7 中最常用的扩展方法:
第一种扩展方法是我最喜欢的一种。 您有多少次在刚刚创建的方法周围添加 try-catch 块,并且因为它破坏了外观而变得有点恼火? 当您的方法返回 Task 或 Task
public static async Task TryAsync(
this Task task,
Action errorHandler = null
) {
try {
await task;
return Result.Ok();
}
catch (Exception ex) {
if (errorHandler is not null) errorHandler(ex);
return ex;
}
}
public static async Task> TryAsync(
this Task task,
Action errorHandler = null
) where T : class {
try {
return await task;
}
catch (Exception ex) {
if (errorHandler is not null) errorHandler(ex);
return ex;
}
}
现在你可以这样写:
var result = await GetSomethingAsync().TryAsync();
您的方法将自动包装在 try-catch 块中。 此外,您可以为其他辅助逻辑(如日志记录)提供 errorHandler。 然后可以检查这些方法返回的结果是否成功,后续您可以继续您的逻辑。
集合中有多个 Task 或 Task
public static async Task> WhenAllAsync(this IEnumerable> tasks) {
if (tasks is null)
throw new ArgumentNullException(nameof(tasks));
return await Task
.WhenAll(tasks)
.ConfigureAwait(false);
}
public static Task WhenAllAsync(this IEnumerable tasks) {
if (tasks is null)
throw new ArgumentNullException(nameof(tasks));
return Task
.WhenAll(tasks);
}
现在我可以方便的地处理任何任务集合:
var results = await tasks.WhenAllAsync();
下一个扩展方法甚至可以为您节省几行代码,并让您能够逐个执行每个任务。 这在您可能不会并行执行许多任务的情况下很有用。
public static async Task> WhenAllSequentialAsync(this IEnumerable> tasks) {
if (tasks is null)
throw new ArgumentNullException(nameof(tasks));
var results = new List();
foreach (var task in tasks)
results.Add(await task.ConfigureAwait(false));
return results;
}
public static async Task WhenAllSequentialAsync(this IEnumerable tasks) {
if (tasks is null)
throw new ArgumentNullException(nameof(tasks));
foreach (var task in tasks)
await task.ConfigureAwait(false);
}
最后但同样重要的是,可能有一个用例,您可以并行执行任务,但可能有最大数量限制。 对于这种情况,我有以下扩展方法:
public static async Task> WhenAllParallelAsync(
this IEnumerable> tasks,
int degree
) {
if (tasks is null)
throw new ArgumentNullException(nameof(tasks));
var results = new List();
foreach (var chunk in tasks.Chunk(degree)) {
var chunkResults = await Task.WhenAll(chunk).ConfigureAwait(false);
results.AddRange(chunkResults);
}
return results;
}
public static async Task WhenAllParallelAsync(
this IEnumerable tasks,
int degree
) {
if (tasks is null)
throw new ArgumentNullException(nameof(tasks));
foreach (var chunk in tasks.Chunk(degree))
await Task.WhenAll(chunk).ConfigureAwait(false);
}
使用 degree 参数,您可以指定应并行执行多少个任务。
这也是一个流畅的扩展,但这次是针对单个 Task 或 Task
public static async Task MapAsync(
this Task task,
Func> mapAsync
) {
if (task is null)
throw new ArgumentNullException(nameof(task));
if (mapAsync is null)
throw new ArgumentNullException(nameof(mapAsync));
return await mapAsync(await task);
}
public static async Task MapAsync(
this Task task,
Func map
) {
if (task is null)
throw new ArgumentNullException(nameof(task));
if (map is null)
throw new ArgumentNullException(nameof(map));
return map(await task);
}
使用此扩展方法,您可以将 Task
类似的方法是 DoAsync() ,但不是转换任务,而是可以使用任务结果执行辅助逻辑而不改变其返回值。
public static async Task DoAsync(
this Task task,
Func tapAsync
) {
if (task is null)
throw new ArgumentNullException(nameof(task));
if (tapAsync is null)
throw new ArgumentNullException(nameof(tapAsync));
var res = await task;
await tapAsync(res);
return res;
}
public static async Task DoAsync(
this Task task,
Action tap
) {
if (task is null)
throw new ArgumentNullException(nameof(task));
if (tap is null)
throw new ArgumentNullException(nameof(tap));
var res = await task;
tap(res);
return res;
}
最后一个是我有时用于连接字符串以进行日志记录的扩展方法。 通常,您可以为此使用 string.Join() ,但同样,这并不流畅,让我无法理解。
public static string Join(this IEnumerable sequence, string separator = "") {
return string.Join(separator, sequence);
}
技术上不是扩展方法,但对节省一些代码也很有用,以下是我的缩写方法:
namespace System;
public static class Abbreviations
{
public static IEnumerable Arr(params T[] elements) => elements;
public static void Try(
Action action,
Action? errorHandler = null
) {
try {
action();
}
catch (Exception ex) {
if (errorHandler is not null) errorHandler(ex);
}
}
public static Result Try(
Func action,
Action? errorHandler = null
) where T : class
{
try {
return action();
}
catch (Exception ex) {
if (errorHandler is not null) errorHandler(ex);
return ex;
}
}
}
要轻松使用它们,您必须在根级别创建一个特殊文件(我通常将其称为 GlobalUsings.cs)并在其中放入以下行:
global using static System.Abbreviations;
Arr 方法是从现有值创建新 IEnumerable
var arr = new [] { param1, param2,... };
现在你可以这样写:
var arr = Arr(param1, param2,... );
哪个看起来更漂亮?
您有多少次只是想在一个新方法周围添加一个简单的 try-catch 块,但由于它在您的代码中占用了太多空间,所以感觉很难看? 这是一个缩写方法 Try() 的解决方案。
在最短的形式中,你可以写:
Try(TestMethod);
其中 TestMethod 是一个不带任何参数的方法。 这使您能够编写极短的代码并消除那些讨厌的 try-catch 块。
对于异步方法,我建议您使用上面的扩展方法 TryAsync,因为它是流畅的风格。
当然,还有更多的可能性,您可以使用此架构并制作自己的缩写词和扩展方法。 在评论中让我知道你的想法。
我希望您发现其中一些方法有用并将它们应用到您的项目中。
谢谢阅读!
页面更新:2024-03-07
本站资料均由网友自行发布提供,仅用于学习交流。如有版权问题,请与我联系,QQ:4156828
© CopyRight 2020-2024 All Rights Reserved. Powered By 71396.com 闽ICP备11008920号-4
闽公网安备35020302034903号