在不破坏代码的情况下重命名接口
本文关键字:情况下 重命名 接口 代码 | 更新日期: 2023-09-27 18:17:36
如果我想重命名一个接口而不破坏现有的代码,这会工作吗?
旧接口:
namespace RenameInterfaceNicely
{
/// <summary>
/// The old name of the interface.
/// </summary>
[Obsolete("IFoo is replaced by IFooNew.")]
public interface IFoo
{
void Test();
}
}
重新命名的新接口:
namespace RenameInterfaceNicely
{
#pragma warning disable 0618
/// <summary>
/// IFooNew new name for the interface IFoo.
/// </summary>
public interface IFooNew : IFoo
{
}
#pragma warning restore 0618
}
所以如果我有一个使用旧接口的类Foo,我现在改变为使用新接口。Foo的用户会遇到麻烦吗?
修改前:
public class Foo : IFoo
{
public void Test()
{
// Do something
return;
}
}
修改后的Foo:
public class Foo : IFooNew
{
public void Test()
{
// Do something
return;
}
}
现有代码示例:
// Old code
IFoo oldFoo = new Foo();
oldFoo.Test();
IFoo oldFoo2 = new Bar().GetFoo();
...
Bar bar = new Bar();
bar.DoSomethingWithFoo(oldFoo);
新代码示例:
// New code
IFooNew newFoo = new Foo();
newFoo.Test();
IFooNew newFoo2 = new Bar().GetFoo();
...
Bar bar = new Bar();
bar.DoSomethingWithFoo(newFoo);
我的问题是受这个启发的:关于。net中api破坏变化的权威指南而且有人做了一个突破性的改变,重命名了我正在使用的一些界面
在真正重命名的情况下:每个人都需要重新编译以获取该更改。坦率地说,这是一个危险的变化。接口是契约,不应该重命名为。然而,如果重命名是不可避免的,这至少让他们知道要将其更改为什么。
,
然而,实际上:你所演示的并不是一个重命名;这是一种半强制性的延期;IFoo
仍然存在,仍然具有旧的功能。假设您希望人们开始提供IFooNew
实现。这是合理的,但是您应该确保如果消费者仅实现IFoo
,那么它将继续工作。
重命名公共类型或成员是一个破坏性的更改。
- 你没有得到源代码兼容性。明确提到接口名称的源代码,需要修改。
- 相同解决方案中的依赖代码可以通过重命名重构自动更改
- 您可以使用类型转发保留依赖于接口工作的二进制代码。这是为在程序集之间移动类型而不是重命名而设计的,所以我不确定它是否有效。
从旧接口派生一个新接口仍然是坏的:
- 当显式实现一个方法时,你需要在 中引用该方法的类型
- 实现旧接口的类不能实现新接口。
- 返回旧接口的代码仍将返回旧接口
您可能需要考虑将IFoo
的定义复制到IFooNew
中,而不是将其作为子接口实现。这可能使以后删除IFoo
更容易,特别是如果有人显式地实现了该接口。
考虑以下内容:
public class Foo : IFoo {
void IFoo.Test() {}
}
升级到你的新版本(v2)后,他们现在会得到你的Obsolete
编译器警告,在某种程度上,希望他们会改变,所以他们实现IFooNew
而不是IFoo
,并改变所有引用。但是由于他们使用显式实现,他们必须将实现保留为IFoo.Test
而不是IFooNew.Test
:
public class Foo : IFooNew {
void IFoo.Test() {}
}
它们不再得到编译器警告,一切都很好。在库的下一个版本(v3)中,您将Test
方法移到IFooNew
中,消除IFoo
,现在它们再次升级到您的最新版本-它们现在必须再次更改代码。
public class Foo : IFooNew {
void IFooNew.Test() {}
}
理想情况下,你只会强迫他们修改一次代码而不是两次。