阶段一:巩固基础之一委托/Lambda

1. 委托(Delegate)的本质

1.1 委托是什么?
  • 定义:委托是类型安全的函数指针,用于封装具有特定签名的方法。

  • 核心特点

    • 可指向任何签名匹配的方法(静态方法或实例方法)

    • 支持多播(通过+=/-=添加多个方法)

    • 是.NET事件机制的基础

1.2 委托的声明与使用

// 声明委托类型
public delegate int MathOperation(int a, int b);

class Program
{
    static int Add(int a, int b) => a + b;
    static int Multiply(int a,int b) => a * b;

    static void Main()
    {
        // 委托实例化
        MathOperation op = Add;
        Console.WriteLine(op(2, 3)); // 输出 5

        // 多播委托
        op += Multiply;
        Console.WriteLine(op(2, 3)); // 输出 5(最后一个方法的返回值)
    }
}
1.3 内置通用委托
  • Action:无返回值的委托(最多16个参数)

  • Func:有返回值的委托(最后一个泛型参数是返回值类型)

  • Predicate<T>:返回bool的委托(常用于集合筛选)

// 使用内置委托
Func<int, int, int> addDelegate = (x, y) => x + y;
Action<string> logDelegate = msg => Console.WriteLine(msg);

2.2 Lambda的两种形式
  1. 表达式Lambda(单行代码)

    Func<int, bool> isEven = n => n % 2 == 0;
  2. 语句Lambda(多行代码,用{}包裹)

    Action<string> print = msg => 
    {
        Console.WriteLine($"Log: {msg}");
        File.WriteAllText("log.txt", msg);
    };
2.3 闭包(Closure)
  • 现象:Lambda可以捕获外部变量(包括局部变量、参数、甚至this)

  • 本质:编译器生成匿名类来包装捕获的变量

void ClosureDemo()
{
    int factor = 2;
    Func<int, int> multiplier = n => n * factor;
    factor = 3; // 闭包捕获的是变量的引用
    Console.WriteLine(multiplier(5)); // 输出15
}

3. 委托与Lambda的高级应用

3.1 事件驱动编程
public class FileWatcher
{
    // 定义事件(基于EventHandler委托)
    public event EventHandler<FileEventArgs> FileChanged;

    public void Start()
    {
        FileSystemWatcher watcher = new FileSystemWatcher();
        watcher.Created += (sender, e) => 
            FileChanged?.Invoke(this, new FileEventArgs(e.FullPath));
    }
}

// 使用
var watcher = new FileWatcher();
watcher.FileChanged += (sender, e) => Console.WriteLine($"File created: {e.FilePath}");
3.2 LINQ的基石

var numbers = new List<int> { 1, 2, 3, 4, 5 };

// Where方法接收Func<int, bool>委托
var evenNumbers = numbers.Where(n => n % 2 == 0);

// 自定义LINQ操作符
public static IEnumerable<T> Where<T>(this IEnumerable<T> source, Func<T, bool> predicate)
{
    foreach (var item in source)
    {
        if (predicate(item)) yield return item;
    }
}

3.3 回调机制

// 异步操作完成回调
public void DownloadFile(string url, Action<string> onCompleted)
{
    Task.Run(() => 
    {
        // 模拟下载
        Thread.Sleep(1000);
        onCompleted?.Invoke($"Downloaded: {url}");
    });
}

// 使用
DownloadFile("http://example.com", result => Console.WriteLine(result));

4. 表达式树(Expression Trees)

4.1 将Lambda转换为数据
  • 表达式树:将Lambda表达式编译成可遍历的树形数据结构

  • 应用场景:Entity Framework的LINQ to SQL转换

  • // 将Lambda转换为表达式树
    Expression<Func<int, bool>> expr = num => num > 5;
    
    // 解析表达式树
    var param = expr.Parameters[0];          // num
    var operation = expr.Body as BinaryExpression;  // > 
    var right = operation.Right as ConstantExpression; // 
    
4.2 动态生成Lambda
// 动态构建 num => num > 5
ParameterExpression param = Expression.Parameter(typeof(int), "num");
ConstantExpression constant = Expression.Constant(5);
BinaryExpression comparison = Expression.GreaterThan(param, constant);
Expression<Func<int, bool>> lambda = 
    Expression.Lambda<Func<int, bool>>(comparison, param);

// 编译并执行
Func<int, bool> func = lambda.Compile();
Console.WriteLine(func(10)); // 输出True

5. 实战技巧与陷阱

5.1 委托与内存泄漏
  • 问题:事件订阅导致对象无法被GC回收

  • 解决方案

    // 弱事件模式
    public class WeakEvent<TEventArgs>
    {
        private List<WeakReference<EventHandler<TEventArgs>>> _handlers = new List<WeakReference<EventHandler<TEventArgs>>>();
        
        public void AddHandler(EventHandler<TEventArgs> handler)
        {
            _handlers.Add(new WeakReference<EventHandler<TEventArgs>>(handler));
        }
        
        public void Raise(object sender, TEventArgs e)
        {
            foreach (var weakRef in _handlers.ToList())
            {
                if (weakRef.TryGetTarget(out var handler))
                    handler(sender, e);
                else
                    _handlers.Remove(weakRef);
            }
        }
    }
5.2 异步Lambda
// 异步事件处理
button.Click += async (sender, e) => 
{
    await Task.Delay(1000);
    MessageBox.Show("Clicked!");
};
5.3 性能优化
  • 避免重复编译表达式树:缓存已编译的委托

  • 慎用闭包:在循环中捕获变量可能导致意外结果

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值