.NET 中的扩展方法






4.72/5 (61投票s)
.NET 中扩展方法的简介及示例
引言
在本文中,我们将探讨什么是扩展方法以及如何在 .NET 中使用它们。就可读性而言,我认为它们是 .NET 框架中最棒的特性之一。我将向您介绍扩展方法是什么,如何创建它们(在 C# 和 VB 中),然后向您展示一些我创建的扩展方法(仅 C#,转换部分留给您尝试)。
目录
什么是扩展方法?
扩展方法允许您轻松地扩展一个类型,例如 integer
或 string
,而无需重新编译或修改该类型。本质上,它们是一种 static
(VB 中为 shared
)方法,但调用方式就像该方法是该类型原生提供的一样。扩展方法从 .NET Framework 3.5 版本开始可用,并且可以应用于 .NET Framework 中的任何类型或您定义的任何自定义类型。
扩展方法的一个缺点是,如果您创建了一个与某个类型中现有方法同名的扩展方法,编译器会将方法调用绑定到原生方法,而不是扩展方法。仅当找不到原生方法时,才会调用扩展方法。
警告
如何创建扩展方法?
创建扩展方法的基本轮廓如下:
- 创建一个
public static
类(VB 中为module
) - 定义您希望执行的函数
- 将函数设为扩展方法
通过一个完整的示例,我现在将演示如何创建一个返回字符串前 3 个字符的扩展方法。根据上面的列表,我首先需要创建一个 static class
或 module
。
// C#
public static class Extensions
{
}
' VB
Module Extensions
End Module
接下来的阶段是编写我们将需要的函数,在这种情况下是以下代码:
// C#
public static class Extensions
{
public string GetFirstThreeCharacters(String str)
{
if(str.Length < 3)
{
return str;
}
else
{
return str.Substring(0,3);
}
}
}
' VB
Module Extensions
Public Function GetFirstThreeCharacters(Byval str As String) As String
If (str.Length < 3) Then
return str
Else
return str.SubString(0,3)
End If
End Function
End Module
到目前为止,我们没有做任何特殊的事情。最后一个阶段是将函数设为扩展方法。VB 中的实现稍微复杂一些,但差别不大。我将先处理 C#。
为了实现我们的 C# 版本函数,我们需要一个扩展方法来将函数标记为 static
(以便无需声明任何内容即可随时访问),其次,用 this
关键字标记第一个参数。这个关键字基本上告诉 CLR,当调用此扩展方法时,将“this
”参数作为源。请看以下代码:
public static class Extensions
{
public static string GetFirstThreeCharacters(this String str)
{
if(str.Length < 3)
{
return str;
}
else
{
return str.Substring(0,3);
}
}
}
现在是 VB 版本。我们不需要使用 this
关键字,而是需要做一些稍微不同的事情。我们需要用 System.Runtime.CompilerServices.Extension
属性标记函数,如下所示:
<System.Runtime.CompilerServices.Extension> _
Public Function GetFirstThreeCharacters(Byval str As String) As String
If str.Length < 3 Then
Return str
Else
Return str.Substring(0, 3)
End If
End Function
如果您将此代码复制到任何项目中,您应该可以像这样调用它:
// C#
String str = "my new String";
str = str.GetFirstThreeCharacters();
' VB
Dim str as String = "my new String"
str = str.GetFirstThreeCharacters()
正如我在上面为两种语言所解释的,this
关键字的有效使用使 CLR 将我们调用扩展方法的对象作为函数的第一个参数。
提示:尝试添加一个额外的 Integer
参数,并将其用作上面代码中 0 的替代。
扩展方法示例
以下是一些我随着时间推移发现或创建的扩展。它们对我很有帮助,我希望对您也同样有帮助。如果您对其中任何一个有疑问,请在下方给我留言。
HasElements
我经常做的一件事是检查集合中是否存在某个值。此方法旨在避免我不断检查 null
值以及给定集合中是否存在任何项。此方法适用于实现 ICollection
接口的任何集合。
定义
/// <summary>
/// Determines whether the specified collection has any elements in the sequence.
/// This method also checks for a null collection.
/// </summary>
/// <param name="items">The ICollection of items to check.</param>
public static bool HasElements(this ICollection items)
{
return items != null && items.Count > 0;
}
Example usage
List<String> myList = new List<String>();
if (myList.HasElements())
{
// do some code
}
IsBetween
IsBetween
方法返回一个布尔值,并确定一个值是否在包含上下边界之间。这仅适用于实现 IComparable
接口的类型。
定义
/// <summary>
/// Determines whether a value is between a minimum and maximum value.
/// </summary>
/// <typeparam name="T">The type of the value parameter.</typeparam>
/// <param name="value">The value that needs to be checked.</param>
/// <param name="low">The inclusive lower boundary.</param>
/// <param name="high">The inclusive upper boundary.</param>
public static bool IsBetween<T>(this T value, T low, T high) where T : IComparable<T>
{
return value.CompareTo(low) >= 0 && value.CompareTo(high) <= 0;
}
Example usage
Int32 myInt = 0;
myInt.IsBetween(0, 5); // returns true
myInt.IsBetween(1, 5); // returns false
Each
我经常需要对项目集合执行一项任务。这只是一个简写的方式,表示对集合中的每个元素执行此操作。这适用于实现 ICollection
接口的任何集合。传入的操作可以是 lambda 表达式或函数/子过程。
定义
/// <summary>
/// Executes the given action against the given ICollection instance.
/// </summary>
/// <typeparam name="T">The type of the ICollection parameter.</typeparam>
/// <param name="items">The collection the action is performed against.</param>
/// <param name="action">The action that is performed on each item.</param>
public static void Each<T>(this ICollection<T> items, Action<T> action)
{
foreach (T item in items)
{
action(item);
}
}
Example usage
List<String> myList = new List<String>();
myList.Each(el =>
{
// perform an action(s) on the item
el.Substring(0,1);
el = el;
});
In
通常有必要确定一个值是否存在于某个集合中。例如,我需要检查一个 string
是否在一个允许的列表中。此方法允许我们将任何值与相同类型的数组值进行比较。
定义
/// <summary>
/// Determines whether a parameter is in a given list of parameters.
/// E.g.. 11.In(1,2,3) will return false.
/// </summary>
/// <typeparam name="T">The type of the source parameter.</typeparam>
/// <param name="source">The item that needs to be checked.</param>
/// <param name="list">The list that will be checked for the given source.</param>
public static bool In<T>(this T source, params T[] list)
{
if (null == source) throw new ArgumentNullException("source");
return list.Contains(source);
}
Example usage
Int32 myInt = 0;
myInt.In(0, 0, 1, 2, 3); // returns true
myInt.In(1, 5, 6, 7, 8); // returns false
希望您现在已经了解了如何在 C# 和 VB.NET 中实现扩展方法。如果您在扩展方法方面需要任何帮助,或者想提问,请在下方给我留言。
相关链接
历史
- 2011 年 9 月 28 日:初始版本
- 2011 年 9 月 29 日:修复了文章文本中的一个编译器错误。源代码没有问题。