cad.net 委托

定义

委托就是函数指针,就是回调函数.
它用了一个函数指针链构成多播,
这样才可以+=和-=,是事件实现底层,
不过事件要event关键字才可以反射到.
视频参考

它形成了一种夹芯饼干式的编程方法,
饼干的两端是固定的,把芯的内容抛出去给调用的人.

为什么这么做呢?
我认为最重要的是写SDK的,和调用者不是同一个人,
但是写SDK的人想调用者写的函数插在这个函数的中间.

无返回值的Action

/// <summary>
/// 事务委托
/// </summary>
/// <param name="db">数据库对象</param>
/// <param name="ac">委托,输出事务</param>
/// <param name="commit">是否提交,默认提交</param>
public static void Action(this Database db, Action<Transaction> ac, bool commit = true) {
    var tr = db.TransactionManager.StartTransaction();
    try {
        ac.Invoke(tr); // 事务就被传出去了
    } catch (Exception e) {
        Debugger.Break();
    } finally {
        if (tr != null && !tr.IsDisposed) {
            if (commit && tr.TransactionManager.NumberOfActiveTransactions > 0)
                tr.Commit();
            tr.Dispose();
        }
    }
}

调用:

db.Action(tr => { ... });

但是这样写函数有几个缺点,
调用的时候需要套入函数体内,这样比较丑.
为什么说丑?
因为增加了一层大括号,圈复杂度变高,
很多时候委托内还有委托,嵌套好几层....

这个事务委托改用新版语法的using,你就发现这样更美.

void Test() {
    using var tr = db.TransactionManager.StartTransaction();
    ...
    tr.Commit();
}

关于事务,我们已经从 事务委托 改为 事务栈

有返回值的Func

// 功能是搜索第一个满足条件,然后中断搜索.
// bool就是返回值类型
public int MyFirst(List<int> list, Func<int, bool> func) {
    foreach(var item in list) {
        var flag = func(item);
        if (flag) return item;
    }
    // 没有成功选中,会返回默认值.
    return default;
}

// 调用
public static void Main() {
    var list = new List<int>() { 1,2,3,4,5,6,7,8,9 };
    var result = MyFirst(list, a => a == 3);
    // 没有成功选中,会返回默认值.
    if (result == default)
       return;
}

我上面实现了一个int版本,
而微软在Linq实现是泛型版本,更通用:

// 泛型版本
var result = list.FirstOrDefault(a => a==3);
// 它速度快,内部是for而不是foreach,
// 它是List专用,Array/HashSet/Dictionary就用不了.
var result = list.Find(a => a==3);
// 下面这个,它找不到会报错,最好别用
var result = list.First(a => a==3);

技巧

实际上我们不喜欢Func,但是我们需要这个中断标记.
那么怎么办呢?
1, 结构体是值类型会被拷贝值,外部改了内部也没变,除非ref.
2, 类是引用类型,所以传输出去之后内部和外部都是同一个.
那么要是Action的其中一个参数是类就好了.

LoopState类也在事务栈

public int MyFirst(List<int> list, Action<int, LoopState> func) {
    LoopState state = new();
    foreach(var item in list) {
        func(item, state);
        if (!state.IsRun) return item;
    }
    // 没有成功选中,会返回默认值.
    return default;
}

// 调用
public static void Main() {
    var list = new List<int>() { 1,2,3,4,5,6,7,8,9 };
    var result = MyFirst(list, (a, state) => {
        if (a == 3)
            state.Break();
    });
    // 没有成功选中,会返回默认值.
    if (result == default)
       return;
}

(完)

posted @   惊惊  阅读(2052)  评论(1编辑  收藏  举报
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
点击右上角即可分享
微信分享提示