使用“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,那就太好了。
更简单的解决方案可能是使用一个通用接口:
public interface IFooBox<T>
where T : IFoo
{
T Foo { get; }
}
您可以为您的基本对象设置一个IFooBox<IFoo>
,或为增强版本设置一个IFooBox<IEnhancedFoo>
。
这种类型的定义将迫使IEnhancedFooBox
的实实者显式地将IFoo.Foo
与IEnhancedFooBox.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,将无法获得预期的输出。使用泛型可以解决这个问题。