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

C#中如何通过接口默认实现实现实体审计的自动调用

优化方案

方案1:在基类BaseEntity中统一处理审计逻辑

既然所有实体都继承自BaseEntity,可以直接在基类构造函数中检查当前实例是否实现IAuditable,若实现则自动触发审计逻辑,从根源避免子类手动调用的遗漏问题。同时通过构造注入解决userNameProvider的依赖传递:

// 定义用户信息提供者接口
public interface IUserNameProvider
{
    Guid GetUserId();
}

// 修改基类逻辑
public abstract class BaseEntity
{
    public Guid Id { get; } = Guid.NewGuid();

    protected BaseEntity(IUserNameProvider userNameProvider)
    {
        if (this is IAuditable auditable)
        {
            auditable.CreatedBy = userNameProvider.GetUserId();
            auditable.Audit();
        }
    }
}

// 调整IAuditable接口,拆分职责
public interface IAuditable
{
    DateTime CreatedTime { get; set; }
    Guid CreatedBy { get; set; }

    void Audit()
    {
        CreatedTime = DateTime.UtcNow;
    }
}

// 子类只需继承+实现接口,无需手动处理审计
public class Car : BaseEntity, IAuditable
{
    public string Name { get; private set; }
    public DateTime CreatedTime { get; set; }
    public Guid CreatedBy { get; set; }

    public Car(string name, IUserNameProvider userNameProvider) 
        : base(userNameProvider)
    {
        Name = name;
    }
}

所有继承BaseEntity且实现IAuditable的实体,实例化时都会自动执行审计逻辑,无需子类编写额外代码,也避免了类型转换操作。

方案2:用泛型工厂封装实体创建逻辑

如果不想修改基类构造,可通过泛型工厂统一管理实体创建流程,确保审计逻辑被强制执行:

public interface IEntityFactory
{
    T Create<T>(Func<T> factoryMethod) where T : BaseEntity;
}

public class EntityFactory : IEntityFactory
{
    private readonly IUserNameProvider _userNameProvider;

    public EntityFactory(IUserNameProvider userNameProvider)
    {
        _userNameProvider = userNameProvider;
    }

    public T Create<T>(Func<T> factoryMethod) where T : BaseEntity
    {
        var entity = factoryMethod();
        
        if (entity is IAuditable auditable)
        {
            auditable.CreatedBy = _userNameProvider.GetUserId();
            auditable.Audit();
        }

        return entity;
    }
}

// 使用示例
var factory = new EntityFactory(new DefaultUserNameProvider()); // 替换为实际实现
var car = factory.Create(() => new Car("bmw"));

这种方式无需修改基类,所有实体创建都通过工厂完成,既能保证审计逻辑不遗漏,也可扩展其他公共创建逻辑。

额外优化:强化审计属性的安全性

可将CreatedTime和CreatedBy的外部访问权限设为只读,仅允许内部逻辑修改,避免外部随意篡改:

public interface IAuditable
{
    DateTime CreatedTime { get; }
    Guid CreatedBy { get; }

    void Audit(Guid createdBy)
    {
        (this as IAuditableInternal).CreatedTime = DateTime.UtcNow;
        (this as IAuditableInternal).CreatedBy = createdBy;
    }
}

// 内部接口用于属性设置
internal interface IAuditableInternal
{
    DateTime CreatedTime { get; set; }
    Guid CreatedBy { get; set; }
}

// 子类实现双接口
public class Car : BaseEntity, IAuditable, IAuditableInternal
{
    public string Name { get; private set; }
    DateTime IAuditable.CreatedTime { get; }
    Guid IAuditable.CreatedBy { get; }
    DateTime IAuditableInternal.CreatedTime { get; set; }
    Guid IAuditableInternal.CreatedBy { get; set; }

    public Car(string name, IUserNameProvider userNameProvider) 
        : base(userNameProvider)
    {
        Name = name;
    }
}

外部代码仅能读取审计属性,无法直接修改,保证审计数据的完整性。

内容的提问来源于stack exchange,提问作者Simon Great

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 18:50:41