实现接口与添加新方法之间有区别吗?
Is there a difference between implementing an interface vs adding a new method?
如下面的代码所示,在两个不同的程序集中定义了两个接口IFoo
:
/// assembly A
interface IFoo {
void DoSomething()
}
/// assembly B
interface IFoo {
void DoSomething()
void DoSomethingElse()
}
/// assembly C
class Bar : IFoo {
public virtual void DoSomething()
public virtual void DoSomethingElse()
}
假设程序集 A 和程序集 B 错误地具有相同的签名(程序集弱名称或强名称)。为 class Bar
生成的 MSIL 是否会有所不同,具体取决于在构建期间使用的是程序集 A 还是程序集?
换句话说,假设我们在 运行 时用程序集 A 和 C 构建一个项目,在 运行 时用程序集 B 替换 A 是否可以?或者我会得到类似 "IFoo.DoSomethingElse" 未实现的异常,因为在构建过程中 DoSomethingElse
被认为是一种新方法,而不是在接口中实现现有方法。
接口映射是在构建时创建的,如果 "assembly A"(1 种方法)在构建时使用,那么 Foo
class 只会在其接口映射中映射一种方法。
创建 class 的实例时,它将尝试使用在 运行 时可用的接口(这不一定与编译时使用的接口相同,如您的情况)并将无法映射新的第二种方法。
在 C# 8 之前确实没有解决它的好方法 - 您要么必须降级依赖项以使其接口向后兼容,要么使用新版本的依赖项重新编译您的代码。
如果预计这是一个常见问题,您可以考虑使用方法的默认实现从 "assembly A" 公开基础 class,以允许添加接口方法并从中派生 Foo
class 而不是界面。
正如 Hans Passant 指出的那样,C# 8 引入了 default interface methods 来解决那个确切的问题。
如下面的代码所示,在两个不同的程序集中定义了两个接口IFoo
:
/// assembly A
interface IFoo {
void DoSomething()
}
/// assembly B
interface IFoo {
void DoSomething()
void DoSomethingElse()
}
/// assembly C
class Bar : IFoo {
public virtual void DoSomething()
public virtual void DoSomethingElse()
}
假设程序集 A 和程序集 B 错误地具有相同的签名(程序集弱名称或强名称)。为 class Bar
生成的 MSIL 是否会有所不同,具体取决于在构建期间使用的是程序集 A 还是程序集?
换句话说,假设我们在 运行 时用程序集 A 和 C 构建一个项目,在 运行 时用程序集 B 替换 A 是否可以?或者我会得到类似 "IFoo.DoSomethingElse" 未实现的异常,因为在构建过程中 DoSomethingElse
被认为是一种新方法,而不是在接口中实现现有方法。
接口映射是在构建时创建的,如果 "assembly A"(1 种方法)在构建时使用,那么 Foo
class 只会在其接口映射中映射一种方法。
创建 class 的实例时,它将尝试使用在 运行 时可用的接口(这不一定与编译时使用的接口相同,如您的情况)并将无法映射新的第二种方法。
在 C# 8 之前确实没有解决它的好方法 - 您要么必须降级依赖项以使其接口向后兼容,要么使用新版本的依赖项重新编译您的代码。
如果预计这是一个常见问题,您可以考虑使用方法的默认实现从 "assembly A" 公开基础 class,以允许添加接口方法并从中派生 Foo
class 而不是界面。
正如 Hans Passant 指出的那样,C# 8 引入了 default interface methods 来解决那个确切的问题。