65.9K
CodeProject 正在变化。 阅读更多。
Home

.NET 中的扩展方法

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.72/5 (61投票s)

2011 年 9 月 28 日

CPOL

4分钟阅读

viewsIcon

179757

downloadIcon

1203

.NET 中扩展方法的简介及示例

引言

在本文中,我们将探讨什么是扩展方法以及如何在 .NET 中使用它们。就可读性而言,我认为它们是 .NET 框架中最棒的特性之一。我将向您介绍扩展方法是什么,如何创建它们(在 C# 和 VB 中),然后向您展示一些我创建的扩展方法(仅 C#,转换部分留给您尝试)。

目录

什么是扩展方法?

扩展方法允许您轻松地扩展一个类型,例如 integerstring,而无需重新编译或修改该类型。本质上,它们是一种 static(VB 中为 shared)方法,但调用方式就像该方法是该类型原生提供的一样。扩展方法从 .NET Framework 3.5 版本开始可用,并且可以应用于 .NET Framework 中的任何类型或您定义的任何自定义类型。

扩展方法的一个缺点是,如果您创建了一个与某个类型中现有方法同名的扩展方法,编译器会将方法调用绑定到原生方法,而不是扩展方法。仅当找不到原生方法时,才会调用扩展方法。

警告

如果您在 Object 类型上声明一个扩展方法,那么您将有效地为框架中的每种类型创建扩展方法,包括但不限于 String、Integer 和 Lists。

如何创建扩展方法?

创建扩展方法的基本轮廓如下:

  1. 创建一个 public static 类(VB 中为 module
  2. 定义您希望执行的函数
  3. 将函数设为扩展方法

通过一个完整的示例,我现在将演示如何创建一个返回字符串前 3 个字符的扩展方法。根据上面的列表,我首先需要创建一个 static classmodule

// 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 日:修复了文章文本中的一个编译器错误。源代码没有问题。
© . All rights reserved.