You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为C#中不同业务对象实现通用的Delete函数

如何为C#中不同业务对象实现通用的Delete函数

我明白你现在的痛点——一堆is判断不仅写起来繁琐,以后加新业务类还要不断修改DeleteItem,完全不符合开闭原则。咱们可以通过几个小步骤来重构,让这个逻辑变得通用且可扩展:

问题背景

我有几个业务类(bizMember、bizParsha和bizEarningYear),它们都继承自泛型基类bizObject<T>。每个类都有一个Delete(int id)方法用来从数据库中删除条目。

目前我写了一个DeleteItem方法,通过is关键字判断传入对象的类型,然后调用对应的Delete方法,但这种方式扩展性很差。我想要一种更通用的处理方式,能让任何继承自bizObject<T>的类传入后自动调用它的Delete方法。

当前实现代码

private async Task DeleteItem(object item)
{
    if (item is bizEarningYear bey)
    {
        await bey.Delete(bey.EarningYearId);
        await _viewmodelbinder.LoadEarningYearList();
    }
    else if (item is bizParsha bp)
    {
        await bp.Delete(bp.ParshaId);
        await _viewmodelbinder.LoadParshaList();
    } 
    else if (item is bizMember m)
    {
        await m.Delete(m.MemberId);
        await _viewmodelbinder.LoadMemberList();
    }
}

private async void Delete_Clicked(object sender, EventArgs e)
{
    if (sender is Button b && await PromptBeforeDelete(b.Parent.BindingContext))
    {
        try
        {
            await DeleteItem(b.Parent.BindingContext);
        }
        catch (Exception ex)
        {
            await DisplayAlert(this.ToString(), ex.Message, "Close");
        }
    }
}

我的需求

  • 去掉那些繁琐的类型检查(is语句),换成可扩展的实现
  • 写一个通用函数,能处理任何bizObject子类,自动调用它的Delete方法

约束条件

  • bizMember、bizParsha、bizEarningYear都继承自bizObject<T>
  • 每个类都有一个Delete(int id)方法,参数是对象自身的ID
  • 删除完成后必须更新_viewmodelbinder中对应的列表

我尝试过的思路

我一开始想用泛型来实现,写了这样的代码:

private async Task DeleteItem<T>(bizObject<T> item) where T : bizObject<T>, new() 
{
    //code here
}

但卡在了按钮点击事件里——当时我不知道点击对象的具体类型,没法把BindingContext转换成对应的泛型类型,所以这个方案走不通。


可行的重构方案

第一步:给基类加上统一的删除契约

首先咱们要让所有bizObject<T>的子类都遵循同一个删除规范。修改基类,新增两个抽象方法:一个用来获取对象的ID,一个是统一的删除入口(或者把现有Delete改成抽象方法):

public abstract class bizObject<T>
{
    // 让子类返回自己的ID属性值
    protected abstract int GetEntityId();

    // 把Delete改成抽象方法,强制子类实现自己的删除逻辑
    public abstract Task Delete(int id);

    // 统一的删除入口,子类不用管这个,只需要实现上面两个方法就行
    public async Task DeleteAsync()
    {
        await Delete(GetEntityId());
    }
}

然后每个子类实现这两个方法,比如bizEarningYear:

public class bizEarningYear : bizObject<bizEarningYear>
{
    public int EarningYearId { get; set; }

    protected override int GetEntityId()
    {
        // 返回自己的ID属性
        return EarningYearId;
    }

    public override async Task Delete(int id)
    {
        // 这里保留你原来的删除数据库逻辑
    }
}

bizParsha和bizMember也是一样的逻辑,分别返回ParshaId和MemberId就行。

第二步:建立类型与列表更新方法的映射

删除后要调用对应的LoadXXXList,咱们可以用一个字典来存“类型”和“对应的列表更新方法”的映射,这样就不用写if-else了。在你的类(比如ViewModel或者页面类)的构造函数里初始化这个字典:

private readonly Dictionary<Type, Func<Task>> _listUpdateActions;

// 假设这是你的类构造函数
public YourClassName()
{
    _listUpdateActions = new Dictionary<Type, Func<Task>>
    {
        { typeof(bizEarningYear), _viewmodelbinder.LoadEarningYearList },
        { typeof(bizParsha), _viewmodelbinder.LoadParshaList },
        { typeof(bizMember), _viewmodelbinder.LoadMemberList }
    };
}

第三步:重构通用的DeleteItem方法

现在DeleteItem就可以写成完全通用的版本了,不需要任何类型检查:

private async Task DeleteItem(object item)
{
    // 先判断是不是bizObject的子类
    if (item is not bizObject<object> businessObject)
    {
        throw new ArgumentException("传入的对象必须是bizObject<T>的子类", nameof(item));
    }

    // 调用统一的删除方法
    await businessObject.DeleteAsync();

    // 根据对象类型找到对应的列表更新方法并执行
    if (_listUpdateActions.TryGetValue(item.GetType(), out var loadListTask))
    {
        await loadListTask();
    }
    else
    {
        // 可选:处理未注册的类型,比如抛出警告或者记录日志
        throw new InvalidOperationException($"没有为类型{item.GetType().Name}注册列表更新方法");
    }
}

可选:用dynamic简化调用(如果不想改基类)

如果暂时没法修改bizObject<T>基类,也可以用dynamic来绕开类型检查,直接调用方法:

private async Task DeleteItem(object item)
{
    dynamic dynamicItem = item;
    // 注意:这种方式依赖子类的ID属性名和Delete方法签名完全一致
    // 比如bizEarningYear的EarningYearId,这里需要统一命名或者用反射获取ID
    await dynamicItem.Delete(dynamicItem.EarningYearId); 

    // 列表更新部分和上面一样
    if (_listUpdateActions.TryGetValue(item.GetType(), out var loadListTask))
    {
        await loadListTask();
    }
}

不过这种方式没有类型安全保障,如果某个子类没有Delete方法或者ID属性名不对,会在运行时报错,所以还是推荐第一种修改基类的方案。


为什么这个方案更可扩展?

以后新增业务类的时候,你只需要做两件事:

  1. 让新类继承bizObject<T>,实现GetEntityId和Delete方法
  2. 在_listUpdateActions字典里加一行新的类型映射
    完全不需要修改DeleteItem方法,完美符合开闭原则,再也不用写一堆if-else了!

备注:内容来源于stack exchange,提问作者sweetbabygang

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.14 10:33:10