使用“new"在继承的接口中隐藏基成员是个好主意吗?

本文关键字:成员 隐藏 好主意 接口 new quot 继承 使用 | 更新日期: 2023-09-27 18:10:00

在派生接口中使用"new"关键字为具有相同名称的属性或方法提供更派生的返回值是否可取?

假设我有一个接口iddocument:

public interface IDocument
{
    IParagraphs Paragraphs { get; }
    IRevisions Revisions { get; }
    IStyles Styles { get; }
}

和一个派生的IRtfDocument。

public interface IRtfDocument: IDocument
{
   string Rtf { get; }
   ...
}

我还为iparagraph, IRevisions和IStyles提供了更多的派生接口:irtfparagraph, IRtfRevisions, IRtfStyles。一些特定于rtf的需求推动了它们的创建。

当我访问RTF文档的段落时,我希望避免将它们转换为irtfparagraph。修改和样式也一样。避免同时拥有"irtfparagraph"answers"iparagraph"也会很好。所以我想做的是:

public interface IRtfDocument : IDocument
{
    new IRtfParagraphs Paragraphs { get; }
    new IRtfRevisions Revisions { get; }
    new IRtfStyles Styles { get; }
    string Rtf { get; }
}

这被认为是好的做法吗?它似乎适合这种情况,但我想让你c#老手运行它。

Update:所以我实际上继续尝试使用在我的界面中描述的"new"。我的RtfDocument类最终需要一个iddocument。样式属性一个IRtfDocument。样式属性。而我可以只使用iddocument。样式属性返回IRtfDocument的值。样式,这感觉不太对,因为我实现了两个属性。

似乎编译器没有考虑到IRtfStyles派生自istyle的事实,所以它坚持认为我两者都有。如果Liskov替换原则能让我实现IRtfDocument,那就太好了。

使用“new"在继承的接口中隐藏基成员是个好主意吗?

更简单的解决方案可能是使用一个通用接口:

public interface IFooBox<T>
    where T : IFoo
{
   T Foo { get; }
}

您可以为您的基本对象设置一个IFooBox<IFoo>,或为增强版本设置一个IFooBox<IEnhancedFoo>

这种类型的定义将迫使IEnhancedFooBox的实实者显式地将IFoo.FooIEnhancedFooBox.Foo的实现分开实现。由于这项工作很繁琐,我倾向于将其保留到泛型接口扩展非泛型接口的情况下。

例如,考虑以下接口:

interface IFutureValue {
    object Result { get; }
}
interface IFutureValue<T> : IFutureValue {
    new T Result { get; }
}

可以通过使用IFutureValue来实现所有"未来值"的通用处理程序,其中使用特定类型的未来值的代码可以使用IFutureValue<T>

要回答这个问题,

这被认为是好的做法吗?

使用new是不允许的,一般来说。然而,就像编程中所有的皱眉一样,这是一个判断问题。如果您发现new的用法在您的上下文中是有意义的,并且您已经排除了其他途径,如@Servy的例子,那么就试试new吧。不过,请准备好为你的决定辩护。

你对新修饰语的使用存在很大的潜在问题。假设我们使用你的接口:

public interface IFoo
{
    string Name { get; set; }
}
public interface IEnhancedFoo : IFoo
{
    int BarCount { get; set; }
}
public interface IFooBox
{
    IFoo Foo { get; set; }
}
public interface IEnhancedFooBox : IFooBox
{
    new IEnhancedFoo Foo { get; set; }
}

构建我们的类:

public class EnhancedFooBox : IEnhancedFooBox
{
    public IEnhancedFoo Foo { get; set; }
    IFoo IFooBox.Foo { get; set; }
}
public class FooBase : IFoo
{
    public string Name { get; set; }
}
public class EnhancedFoo : IEnhancedFoo
{
    public int BarCount { get; set; }
    public string Name { get; set; }
}

构建一些接受接口的方法…

static void Test1(IFooBox myBlah)
{
    myBlah.Foo = new FooBase();
    myBlah.Foo.Name = "FooBase";
}
static void Test2(IEnhancedFooBox myBlah)
{
    myBlah.Foo = new EnhancedFoo();
    myBlah.Foo.Name = "EnhancedFoo";
}

然后使用这个逻辑:

static void Main(string[] args)
{
    var myBlah = new EnhancedFooBox();
    Test2(myBlah); //first assign name to EnhancedFoo
    Test1(myBlah); //second assign name to FooBase
    Console.Write(myBlah.Foo.Name);
    Console.ReadKey();
}

期望的输出是什么?应该是FooBase还是EnhancedFoo?

EnhancedFoo

程序员不知道属性已被修改为new,将无法获得预期的输出。使用泛型可以解决这个问题。