EF上下文SaveChangesAsync重载解析困惑及相关技术问询
关于EF上下文SaveChangesAsync方法重载解析的疑问与解答
代码示例
你在EF上下文类中定义的两个方法:
public override Task<int> SaveChangesAsync(CancellationToken cancellationToken = default)
public virtual async Task<int> SaveChangesAsync(string userId = "")
疑问点
- 为何所有如
await context.SaveChangesAsync()的调用都解析到第二个方法? - VS C#语言服务为何不将它们视为同一方法组?
- 编译器为何不判定这些调用存在歧义?
- 尝试为第二个方法添加
new修饰符时,编译器提示该修饰符无需添加,原因是什么?
解答
1. 无参数调用匹配第二个方法的原因
C#的重载解析逻辑会优先选择当前类直接定义的方法,而非继承(包括重写)来的方法。第二个方法是你在当前上下文类中新增的成员,而第一个是重写基类的方法。当你不传任何参数时,两个方法的可选参数都可以匹配,但编译器会优先选中当前类定义的重载,因此解析到第二个方法。
2. 为何不判定歧义
两个方法的参数类型完全不同(一个是CancellationToken,一个是string),属于合法的重载。当你不传参数时,编译器能明确区分出当前类定义的重载更“优先”,不存在匹配模糊的情况,因此不会判定为歧义。
3. new修饰符无需添加的原因
new修饰符的作用是隐藏基类中同签名的非虚方法,但你新增的方法是同名但参数不同的重载,并非覆盖或隐藏基类的同签名方法。基类的SaveChangesAsync(CancellationToken)是虚方法,你已经通过override重写了它,第二个方法只是同名重载,和基类的方法签名不同,所以不需要new修饰符。
可选的解决方式
如果想让无参数调用匹配重写的基类方法,可以:
- 显式传入默认值:
await context.SaveChangesAsync(default) - 调用时指定参数类型:
await context.SaveChangesAsync((CancellationToken)default) - 修改第二个方法的名称,避免同名重载的混淆
内容的提问来源于stack exchange,提问作者Tanveer Badar
相关产品推荐
相关产品推荐

