C# Extension Methods

https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/extension-methods

扩展方法可以直接给现有的类扩展方法。扩展方法是静态方法,但是它们像扩展类的实例方法一样被调用。对于用C#、F#、VB写的客户端代码,调用现有类中的方法和扩展方法是没有明显区别的。例如,LINQ中的GroupBy, OrderBy, Average等方法就是IEumerable<T>类型的扩展方法。

扩展方法的第一个参数是用this关键词指定的能够调用该方法的类型。下面是微软document上给出的给string类添加扩展方法的例子。

namespace ExtensionMethod
{
    public static class MyExtensions
    {
        public static int WordCount(this string str)
        {
            return str.Split(new char[] {' ','.','?'}, StringSplitOptions.RemoveEmptyEntries).Length;
        }
    }
}

使用时,记得要引用命名空间。现在就像调用string.Count()方法一样可以直接调用string.WordCount()方法了。

using ExtensionMethod;

string s = "Hello Extension Methods";
int i = s.WordCount();
Console.WriteLine(i);
Console.Read();

值得注意的是,扩展方法的优先级低于类中直接定义的方法的优先级。也就是说,如果类中定义了A()方法,又在扩展方法中定义了一个A()方法,那么优先调用的是类中定义的A()方法。

扩展方法通常与Lambda表达式(或称为匿名方法,anonymous functions)一同使用。请看下方的例子(来源于《Pro ASP.NET Core6 Develop Cloud-Ready Web Applications Using MVC, Blazor, and Razor Pages》)

public class Product
    {
        public long? ProductId { get; set; }
        public string Name { get; set; } = String.Empty;
        public string Description { get; set; } = String.Empty;
        public decimal Price { get; set; }
        public string Category { get; set; } = String.Empty;
    }

using System.Collections;
public class ShoppingCart:IEnumerable<Product?>
    {
        public IEnumerable<Product?>? Products { get; set; }
        public IEnumerator<Product?> GetEnumerator() => Products?.GetEnumerator() ?? Enumerable.Empty<Product?>().GetEnumerator();
        IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
    }

上方代码定义了两个类:Product和ShoppingCart。其中ShoppingCart继承自IEnumerable<Product?>。下面定义两个IEnumerable<Product?>类的扩展方法:用于计算购物车内所有商品的总价值的TotalPrices方法和根据特定条件过滤购物车的Filter方法。

public static  class MyExtensions
    {
        public static decimal TotalPrices(this IEnumerable<Product?> products)
        {
            decimal total = 0;
            foreach(Product? prod in products)
            {
                total += prod?.Price ?? 0;
            }
            return total;
        }

        public static IEnumerable<Product?>Filter(this IEnumerable<Product?> productEnum, Func<Product?, bool> selector)
        {
            foreach(Product? prod in productEnum)
            {
                if (selector(prod))
                {
                    yield return prod;
                }
            }
        }
        
    }

使用lambda表达式调用扩展方法

using ExtensionMethod;

ShoppingCart cart = new ShoppingCart()
{
    Products = new List<Product>()
    {
        new Product
        {
            Name = "Kayak", Price = 275M
        },
        new Product
        {
            Name = "Lifejacket", Price = 48.95M
        },
        new Product
        {
            Name="Soccer",Price=60M
        }
    }
};

decimal cartTotal = cart.TotalPrices();
decimal filterPrice = cart.Filter(p => (p?.Price > 50M)).TotalPrices();
Console.WriteLine(cartTotal);
Console.WriteLine(filterPrice);
Console.Read();
posted @ 2022-07-16 14:45  南风小斯  阅读(176)  评论(0编辑  收藏  举报