7

是否建议在派生接口中使用“new”关键字来为具有相同名称的属性或方法提供更多派生的返回值?

假设我有一个接口 IDocument:

public interface IDocument
{
    IParagraphs Paragraphs { get; }

    IRevisions Revisions { get; }

    IStyles Styles { get; }
}

并派生出一个 IRtfDocument。

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

我还为 IParagraphs、IRevisions 和 IStyles 提供了更多衍生接口:IRtfParagraphs、IRtfRevisions、IRtfStyles。许多特定于 RTF 的需求推动了他们的创作。

当我访问 RTF 文档的段落时,我想避免将它们转换为 IRtfParagraphs。修订和样式相同。最好避免同时使用“IRtfParagraphs”和“IParagraphs”。所以我想做是:

public interface IRtfDocument : IDocument
{
    new IRtfParagraphs Paragraphs { get; }

    new IRtfRevisions Revisions { get; }

    new IRtfStyles Styles { get; }

    string Rtf { get; }
}

这被认为是好的做法吗?它似乎适合这种情况,但我想由你们 C# 退伍军人来运行它。

更新:所以我实际上继续尝试使用我的界面中描述的“新”。我的 RtfDocument 类最终需要 IDocument.Styles 属性IRtfDocument.Styles 属性。虽然我可以让 IDocument.Styles 属性返回 IRtfDocument.Styles 的值,但在实现两个属性时感觉不太对劲。

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

4

4 回答 4

7

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

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

然后,您可以IFooBox<IFoo>为您的基本对象或IFooBox<IEnhancedFoo>增强版本提供一个。

于 2013-04-19T19:44:49.757 回答
4

这种类型的定义将迫使 的实现者IEnhancedFooBox显式地IFoo.FooIEnhancedFooBox.Foo. 由于这项工作变得乏味,我倾向于将此保留用于泛型接口扩展非泛型接口的情况。

例如,考虑以下接口。

interface IFutureValue {
    object Result { get; }
}

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

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

于 2013-04-19T19:46:49.560 回答
2

要回答这个问题,

这被认为是好的做法吗?

通常new,不赞成使用. 然而,就像编程中的所有皱眉一样,这是一个判断问题。如果您发现在您的上下文中有意义的用途,并且您已经排除了其他途径,例如 @Servy 的示例,那么请摇滚. 准备好捍卫你的决定。newnew

于 2013-04-19T19:55:23.770 回答
0

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

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?

增强型Foo

程序员不知道该属性已被修改为新的,不会得到预期的输出。这是使用泛型解决的。

于 2013-04-19T20:03:00.267 回答