IRONSOFTWAREHOME

了解 C# 委托

理解 C# 委托

Tim Corey

1h 9m 11s

C# 中的委托是一项强大的功能,但许多开发人员并不熟悉如何有效地使用它们。 Tim Corey 的视频" C# 中的委托 - 实际演示,包括 Action 和 Func "对委托是什么、如何使用它们以及为什么它们有用进行了详尽的解释。

本文将为您提供 Tim 关于 C# 中委托的专家见解,清晰地解释其用法和实际应用。 您将学习委托如何增强代码的灵活性和效率,例如在购物车系统中使用委托的示例。

简介

Tim 介绍了委托的概念,强调了委托在 C# 中的强大功能和多功能性。 他向观众保证,尽管有些术语令人望而生畏,但代表制的基本原理很简单。 Tim 旨在揭开委托的神秘面纱,并介绍 func 和 action 等特殊类型。

应用程序演示

Tim 设置了一个演示应用程序来说明委托的用法。 该解决方案包含三个项目:控制台 UI、演示库和 WinForm UI。 初期重点是控制台用户界面和演示库。

using System;
using System.Collections.Generic;
using System.Linq;

namespace ConsoleUI
{
    class Program
    {
        static ShoppingCartModel cart = new ShoppingCartModel();

        static void Main(string[] args)
        {
            PopulateCartWithDemoData();

            Console.WriteLine($"The total for the cart is {cart.GenerateTotal():C2}");

            Console.ReadLine();
        }

        private static void PopulateCartWithDemoData()
        {
            cart.Items.Add(new ProductModel { ItemName = "Cereal", Price = 3.63M });
            cart.Items.Add(new ProductModel { ItemName = "Milk", Price = 2.95M });
            cart.Items.Add(new ProductModel { ItemName = "Strawberries", Price = 7.51M });
            cart.Items.Add(new ProductModel { ItemName = "Blueberries", Price = 6.75M });
        }
    }
}

public class ShoppingCartModel
{
    public List<ProductModel> Items { get; set; } = new List<ProductModel>();

    public decimal GenerateTotal()
    {
        decimal subtotal = Items.Sum(x => x.Price);

        if (subtotal > 100)
        {
            return subtotal * 0.80M;
        }
        else if (subtotal > 50)
        {
            return subtotal * 0.85M;
        }
        else if (subtotal > 10)
        {
            return subtotal * 0.90M;
        }
        else
        {
            return subtotal;
        }
    }
}

public class ProductModel
{
    public string ItemName { get; set; }
    public decimal Price { get; set; }
}

Tim 解释了演示应用程序的结构和功能:

*购物车模型:表示购物车,其中包含商品列表(ProductModel),并根据小计计算折扣后的总成本。

*产品模型:表示具有名称和价格属性的单个商品。

*控制台应用程序:用演示数据填充购物车,计算总价,并显示总价。

了解折扣

Tim 详细讲解了 GenerateTotal 方法中的折扣逻辑,解释了小计如何决定应用的折扣:

  • 小计超过 100 美元,可享 20% 折扣。
  • 小计超过 50 美元,可享 15% 折扣。
  • 小计超过 10 美元,可享 10% 折扣。
  • 小计金额低于 10 美元不享受折扣。

Tim 使用断点来演示计算和折扣逻辑,确保观众在向代表介绍之前理解基础知识。

解释和创建代表

在本节中,Tim Corey 将深入探讨 C# 中的委托概念,解释其工作原理,并通过实际代码示例演示其用法。

什么是代表?

Tim解释说,委托本质上是一种将方法作为参数传递的方式。 与其传递变量或属性,不如传递方法,这样可以编写更灵活、更可重用的代码。

创建和使用委托

以下是 Tim 对创建和使用委托过程的详细讲解:

1.定义委托

  • 委托定义在类的顶部,指定返回类型和参数类型。
public delegate void MentionDiscount(decimal subtotal);
  • 此委托指定一个返回 void 的方法,该方法接受一个十进制数作为参数。

2.在方法中使用委托

  • 该委托对象用作 ShoppingCartModel 类的 GenerateTotal 方法中的参数。
public decimal GenerateTotal(MentionDiscount mentionDiscount)
{
    decimal subtotal = Items.Sum(x => x.Price);
    
    // Call a method passed as a delegate
    mentionDiscount(subtotal);

    if (subtotal > 100)
    {
        return subtotal * 0.80M;
    }
    else if (subtotal > 50)
    {
        return subtotal * 0.85M;
    }
    else if (subtotal > 10)
    {
        return subtotal * 0.90M;
    }
    else
    {
        return subtotal;
    }
}
C#

3.创建要传递给委托的方法

  • 在 Program 类中创建一个与委托签名匹配的方法。
private static void SubtotalAlert(decimal subtotal)
{
    Console.WriteLine($"The subtotal is {subtotal:C2}");
}
C#

4.调用 GenerateTotal 方法

  • 该方法通过委托传递给 GenerateTotal 方法。
class Program
{
    static ShoppingCartModel cart = new ShoppingCartModel();

    static void Main(string[] args)
    {
        PopulateCartWithDemoData();

        Console.WriteLine($"The total for the cart is {cart.GenerateTotal(SubtotalAlert):C2}");

        Console.ReadLine();
    }

    private static void PopulateCartWithDemoData()
    {
        cart.Items.Add(new ProductModel { ItemName = "Cereal", Price = 3.63M });
        cart.Items.Add(new ProductModel { ItemName = "Milk", Price = 2.95M });
        cart.Items.Add(new ProductModel { ItemName = "Strawberries", Price = 7.51M });
        cart.Items.Add(new ProductModel { ItemName = "Blueberries", Price = 6.75M });
    }
}
C#

运行应用程序

Tim 运行该应用程序来演示委托是如何工作的。 控制台输出显示了购物车的小计和总计,表明 SubtotalAlert 方法已通过委托成功传递和执行。

函数和动作:你可以用委托解决的问题

Tim Corey 随后探讨了 C# 中 func 和 action delegate 的使用。 这些是微软提供的特殊类型的委托,旨在简化泛型委托的使用。

识别问题

Tim 指出了一个常见问题:GenerateTotal 方法中硬编码的折扣逻辑。 这种方法不够灵活,每次折扣规则发生变化时,都需要修改代码、重新编译和重新部署。

public decimal GenerateTotal()
{
    decimal subtotal = Items.Sum(x => x.Price);
    if (subtotal > 100)
    {
        return subtotal * 0.80M;
    }
    else if (subtotal > 50)
    {
        return subtotal * 0.85M;
    }
    else if (subtotal > 10)
    {
        return subtotal * 0.90M;
    }
    else
    {
        return subtotal;
    }
}

介绍 Func 委托

Tim 引入了 func delegate 来解决硬编码折扣问题。 func 委托是一个通用委托,它表示一个方法签名,带有返回类型和最多 16 个输入参数。

1.定义函数委托

  • 函数委托在 GenerateTotal 方法中使用,以动态处理折扣计算。
public decimal GenerateTotal(Func<List<ProductModel>, decimal, decimal> calculateDiscountedTotal)
{
    decimal subtotal = Items.Sum(x => x.Price);
    MentionDiscount(subtotal);

    return calculateDiscountedTotal(Items, subtotal);
}
C#

2.创建折扣计算方法

  • 在 Program 类中创建一个与函数委托签名匹配的方法。
private static decimal CalculateLevelDiscount(List<ProductModel> items, decimal subtotal)
{
    if (subtotal > 100)
    {
        return subtotal * 0.80M;
    }
    else if (subtotal > 50)
    {
        return subtotal * 0.85M;
    }
    else if (subtotal > 10)
    {
        return subtotal * 0.90M;
    }
    else
    {
        return subtotal;
    }
}
C#

3.将方法传递给函数委托

  • CalculateLevelDiscount 方法通过函数委托传递给 GenerateTotal 方法。
class Program
{
    static ShoppingCartModel cart = new ShoppingCartModel();

    static void Main(string[] args)
    {
        PopulateCartWithDemoData();

        Console.WriteLine($"The total for the cart is {cart.GenerateTotal(CalculateLevelDiscount):C2}");

        Console.ReadLine();
    }

    private static void PopulateCartWithDemoData()
    {
        cart.Items.Add(new ProductModel { ItemName = "Cereal", Price = 3.63M });
        cart.Items.Add(new ProductModel { ItemName = "Milk", Price = 2.95M });
        cart.Items.Add(new ProductModel { ItemName = "Strawberries", Price = 7.51M });
        cart.Items.Add(new ProductModel { ItemName = "Blueberries", Price = 6.75M });
    }

    private static decimal CalculateLevelDiscount(List<ProductModel> items, decimal subtotal)
    {
        if (subtotal > 100)
        {
            return subtotal * 0.80M;
        }
        else if (subtotal > 50)
        {
            return subtotal * 0.85M;
        }
        else if (subtotal > 10)
        {
            return subtotal * 0.90M;
        }
        else
        {
            return subtotal;
        }
    }
}
C#

运行应用程序

Tim 演示了修改后的应用程序,表明它运行正常,并能根据提供的逻辑动态计算折扣。

委托和函数之间的区别

Tim 对比了自定义委托和函数委托:

*委托:需要明确定义签名,提供清晰的文档和结构。

*函数:更简洁,但每次都需要指定输入和输出类型,这可能不太清晰。

两种方法都提供了灵活性,但选择取决于具体的使用案例和应用程序的复杂程度。

既然所有工作都在其他地方完成,为什么还要使用委托呢?

Tim Corey 回答了一个关于使用委托的常见问题:如果所有工作似乎都在其他地方完成,为什么还要使用委托呢?

Tim解释说,委托的目的是为代码提供灵活性和可扩展性。 ShoppingCartModel 类中的 GenerateTotal 方法可能不仅仅用于计算折扣。 它还可以处理诸如检查库存可用性、验证购物车内容或其他业务逻辑等任务。 委托允许您传递特定方法以执行特殊任务或自定义行为,而无需更改核心方法。 这使得代码更具模块化,更易于维护。

在以下情况下,委托尤其有用:

  • 动态应用不同的业务规则或逻辑。 保持核心方法的通用性和可重用性。
  • 在不修改核心方法的情况下,针对特定情况实现自定义行为。

行动代表:创建和解释

Tim 介绍了 Action 委托,这是 C# 中的另一种特殊类型的委托。 Action 委托类似于 Func,但它不返回值(即,它返回 void)。

1.创建操作委托

  • 在 GenerateTotal 方法中定义 Action 委托,以处理警报或消息。
public decimal GenerateTotal(Func<List<ProductModel>, decimal, decimal> calculateDiscountedTotal, Action<string> tellUserWeAreDiscounting)
{
    decimal subtotal = Items.Sum(x => x.Price);
    MentionSubtotal(subtotal);

    tellUserWeAreDiscounting("We are applying your discount.");

    return calculateDiscountedTotal(Items, subtotal);
}
C#

2.创建警报方法

  • 定义一个与 Action 委托的签名匹配的方法。
private static void AlertUser(string message)
{
    Console.WriteLine(message);
}
C#

3.将方法传递给操作委托

  • 通过 Action 委托将 AlertUser 方法传递给 GenerateTotal 方法。
class Program
{
    static ShoppingCartModel cart = new ShoppingCartModel();

    static void Main(string[] args)
    {
        PopulateCartWithDemoData();

        Console.WriteLine($"The total for the cart is {cart.GenerateTotal(CalculateLevelDiscount, AlertUser):C2}");

        Console.ReadLine();
    }

    private static void PopulateCartWithDemoData()
    {
        cart.Items.Add(new ProductModel { ItemName = "Cereal", Price = 3.63M });
        cart.Items.Add(new ProductModel { ItemName = "Milk", Price = 2.95M });
        cart.Items.Add(new ProductModel { ItemName = "Strawberries", Price = 7.51M });
        cart.Items.Add(new ProductModel { ItemName = "Blueberries", Price = 6.75M });
    }

    private static decimal CalculateLevelDiscount(List<ProductModel> items, decimal subtotal)
    {
        if (subtotal > 100)
        {
            return subtotal * 0.80M;
        }
        else if (subtotal > 50)
        {
            return subtotal * 0.85M;
        }
        else if (subtotal > 10)
        {
            return subtotal * 0.90M;
        }
        else
        {
            return subtotal;
        }
    }

    private static void AlertUser(string message)
    {
        Console.WriteLine(message);
    }
}
C#

创建匿名方法:匿名委托

Tim 展示了如何使用匿名方法,允许你动态定义方法而无需命名它们。

1.定义匿名方法

  • 与其创建命名方法,不如直接在需要的地方定义方法。
class Program
{
    static ShoppingCartModel cart = new ShoppingCartModel();

    static void Main(string[] args)
    {
        PopulateCartWithDemoData();

        Console.WriteLine($"The total for the cart is {cart.GenerateTotal((items, subtotal) => 
        {
            if (subtotal > 100) return subtotal * 0.80M;
            else if (subtotal > 50) return subtotal * 0.85M;
            else if (subtotal > 10) return subtotal * 0.90M;
            else return subtotal;
        },
        (message) => Console.WriteLine(message)):C2}");

        Console.ReadLine();
    }

    private static void PopulateCartWithDemoData()
    {
        cart.Items.Add(new ProductModel { ItemName = "Cereal", Price = 3.63M });
        cart.Items.Add(new ProductModel { ItemName = "Milk", Price = 2.95M });
        cart.Items.Add(new ProductModel { ItemName = "Strawberries", Price = 7.51M });
        cart.Items.Add(new ProductModel { ItemName = "Blueberries", Price = 6.75M });
    }
}
C#

2.理解语法

  • 匿名方法语法使用=> 运算符(lambda表达式)直接在行内定义方法体。
  • 无需指定返回类型或方法名称。

通过使用委托(包括 Func、Action 和匿名方法),开发人员可以创建更动态、模块化的代码,从而实现灵活且可重用的组件。

在其他项目中使用委托:WinForms

在本部分中,Tim Corey 通过将委托的使用扩展到 WinForms 应用程序来演示委托的强大功能。 这突显了委托如何在各种用户界面 (UI) 环境中促进不同的行为。

设置 WinForms 应用程序

1.带有两个按钮的 WinForm 用户界面

  • 该表单有两个按钮:一个用于演示消息框,一个用于演示文本框。

  • 此外,还包括 ShoppingCartModel 以及用演示数据填充它的方法。

public partial class Dashboard : Form
{
    ShoppingCartModel cart = new ShoppingCartModel();

    public Dashboard()
    {
        InitializeComponent();
        PopulateCartWithDemoData();
    }

    private void PopulateCartWithDemoData()
    {
        cart.Items.Add(new ProductModel { ItemName = "Cereal", Price = 3.63M });
        cart.Items.Add(new ProductModel { ItemName = "Milk", Price = 2.95M });
        cart.Items.Add(new ProductModel { ItemName = "Strawberries", Price = 7.51M });
        cart.Items.Add(new ProductModel { ItemName = "Blueberries", Price = 6.75M });
    }

    private void messageBoxDemoButton_Click(object sender, EventArgs e)
    {
        decimal total = cart.GenerateTotal(SubtotalAlert, CalculateLevelDiscount, PrintOutDiscountAlert);
        MessageBox.Show($"The total is {total:C2}");
    }

    private void textBoxDemoButton_Click(object sender, EventArgs e)
    {
        // Code for TextBox demo will go here
    }
}

创建委托方法

  1. PrintOutDiscountAlert

    • 此方法将用于显示包含折扣信息的提醒。
    private void PrintOutDiscountAlert(string message)
    {
        MessageBox.Show(message);
    }
    C#

2.小计提醒

  • 此方法会在消息框中显示小计。
private void SubtotalAlert(decimal subtotal)
{
    MessageBox.Show($"The subtotal is {subtotal:C2}");
}
C#

3.计算等级折扣

  • 此方法将根据购物车中的商品数量计算折扣。
private decimal CalculateLevelDiscount(List<ProductModel> items, decimal subtotal)
{
    if (items.Count > 3)
    {
        return subtotal - 3M;
    }
    return subtotal - items.Count;
}
C#

将委托与 WinForms 集成

1.在按钮点击事件中使用委托

  • messageBoxDemoButton_Click 方法演示如何将委托传递给GenerateTotal方法,并使用消息框处理结果。
private void messageBoxDemoButton_Click(object sender, EventArgs e)
{
    decimal total = cart.GenerateTotal(SubtotalAlert, CalculateLevelDiscount, PrintOutDiscountAlert);
    MessageBox.Show($"The total is {total:C2}");
}
C#

2.运行应用程序

  • 当单击按钮时,WinForms 应用程序会使用消息框显示小计和总计,从而展示委托的灵活性。

结论

Tim Corey 对 C# 中的委托进行了清晰的解释,涵盖了委托的基础知识、高级用法以及在购物车中使用委托等实际示例。 他展示了委托如何实现灵活且可重用的代码,包括 Func、Action 和匿名方法。 观看完整视频,了解如何在项目中有效地运用委托!

Earn More by Sharing What You Love

Do you create content for developers working with .NET, C#, Java, Python, or Node.js? Turn your expertise into extra income!

Let's Stay in Touch!

Join our newsletter, you’ll get exclusive access on article updates. We value your privacy

Key in blue circle

立即获取免费的 30 天试用版密钥

Your trial license will be sent to your email address

无任何限制。100% 解锁。无需信用卡。

OR
bullet_checked无需信用卡或创建账户无任何限制。100% 解锁。无需信用卡。
  • Logo Aetna
  • Logo NASA
  • Logo GE
  • Logo Porsche
  • Logo USDA
  • Logo Qatar
Join Millions of Engineers who’ve tried Iron Suite
获取您的无义务咨询
填写下面的表格或通过sales@ironsoftware.com
您的资料将始终保密。
深受全球数百万工程师信赖
Iron Software 的客户徽标
立即获取您的免费30 天试用密钥
无需信用卡或创建账户