C# 在不中断代码的情况下重命名接口

C# 在不中断代码的情况下重命名接口,c#,.net,C#,.net,如果我想在不破坏现有代码的情况下重命名一个接口,这行得通吗 旧界面: namespace RenameInterfaceNicely { /// <summary> /// The old name of the interface. /// </summary> [Obsolete("IFoo is replaced by IFooNew.")] public interface IFoo { void T

如果我想在不破坏现有代码的情况下重命名一个接口,这行得通吗

旧界面:

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:

public class Foo : IFoo
{
    public void Test()
    {    
        // Do something       
        return;
    }
}
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);
我的问题是受这个启发的:
有人通过重命名我正在使用的一些接口做了一个坏的改变。

< P>您可能想考虑将定义从<代码> IFoo <代码>复制到<代码> IFOONEW < /代码>,而不是将它作为子接口实现。这可能会使以后更容易删除
IFoo
,尤其是当有人显式实现该接口时

考虑以下几点:

public class Foo : IFoo {
    void IFoo.Test() {}
}
升级到新版本(v2)后,他们现在会收到您的
过时的
编译器警告,希望在某个时候,他们会进行更改,以实现
IFooNew
而不是
IFoo
,并更改所有引用。但是因为他们使用显式实现,所以必须将实现保留为
IFoo.Test
,而不是
IFooNew.Test

public class Foo : IFooNew {
    void IFoo.Test() {}
}
他们不再收到编译器警告,一切正常。在库的下一个版本(v3)中,您将
Test
方法移动到
IFooNew
,消除
IFoo
,现在他们再次升级到您的最新版本-他们现在必须再次更改代码

public class Foo : IFooNew {
    void IFooNew.Test() {}
}

理想情况下,您只能强制他们更改代码一次,而不是两次。

重命名公共类型或成员是一个突破性的更改

  • 您无法获得源代码兼容性。如果源代码明确提到接口名称,则需要对其进行更改
  • 同一解决方案中的依赖代码可以通过重命名重构自动更改
  • 您可能能够保留依赖于使用的接口的二进制代码。这是为在程序集之间移动类型而设计的,不是为了重命名,所以我不确定它是否有效
从旧接口派生新接口仍处于中断状态:

  • 显式实现方法时,需要引用该方法所在的类型
  • 实现旧接口的类不会实现新接口
  • 返回旧接口的代码仍将返回旧接口

如果是真正的重命名:每个人都需要重新编译以获取更改。坦率地说,这是一个危险的变化。接口是契约,不应重命名。但是,如果重命名不可避免,这至少会让他们知道要将其更改为什么

--


然而,事实上:您所演示的不是重命名;这是一种半强制性的延伸;
IFoo
仍然存在,并且仍然具有旧的功能。大概您希望人们开始提供
IFooNew
实现。这是合理的,但您应该确保如果消费者实现
IFoo
,那么它将继续工作。

我们不能不知道类型是如何使用的。这有可能破坏一个程序吗,是的。您对任何公共API所做的任何类型的更改在某种程度上、形状或形式上都是破坏性的更改。如果接口在语义上相同,但在技术上不相关,则无法将实现新接口的对象传递给任何期望旧接口的方法,反之亦然。对于一个广泛分布的库来说,这几乎肯定是不可能的,而且是一个比OP的方法更具破坏性的变化。@Servy也许我误解了。我的印象是,旧的界面最终会被删除,在这种情况下,是的,你绝对会在某个时候造成巨大的破坏性变化,并迫使人们将所有代码切换到你的新界面,以便升级。在这种情况下,我宁愿进行一轮变革,也不愿进行两轮变革。但是,如果原始接口将永远存在,那么我同意你的观点,并将不使用它。我的想法是将Test()方法保留在旧接口中,以便现有代码可以工作。旧界面的所有用户在编译代码时当然会收到警告。我还考虑了一个场景,在这个场景中,可以通过删除IFoo接口并将Test()-方法移动到新接口IFooNew中,在更高版本中(在用户有机会修复代码之后)进行制动更改。