Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using "new" to hide base member in inherited interface: Is it a good idea?

Is it advisable to use the "new" keyword in a derived interface to provide a more-derived return value for a property or method having the same name?

Say I have an interface IDocument:

public interface IDocument
{
    IParagraphs Paragraphs { get; }

    IRevisions Revisions { get; }

    IStyles Styles { get; }
}

And a derived one IRtfDocument.

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

I also have more-derived interfaces for IParagraphs, IRevisions and IStyles: IRtfParagraphs, IRtfRevisions, IRtfStyles. A number of RTF-specific needs drove their creation.

When I access the paragraphs of an RTF document, I'd like to avoid casting them to IRtfParagraphs. Same for revisions and styles. It would also be nice to avoid having both "IRtfParagraphs" and "IParagraphs". So what I'd like to do is this:

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

    new IRtfRevisions Revisions { get; }

    new IRtfStyles Styles { get; }

    string Rtf { get; }
}

Is this considered good practice? It seems to fit in this situation, but I wanted to run it by you C# veterans.

Update: So I actually went ahead and tried using "new" as described in my interfaces. My RtfDocument class ended up needing both an IDocument.Styles property and an IRtfDocument.Styles property. While I could just have the IDocument.Styles property return the value of IRtfDocument.Styles, that doesn't feel quite right as I'm implementing two properties.

It seems the compiler doesn't account for the fact that IRtfStyles derives from IStyles, so it insists I have both. It would be nice if the Liskov Substitution Principle let me just implement IRtfDocument.Styles in the RtfDocument class.

like image 887
System.Cats.Lol Avatar asked Apr 19 '13 19:04

System.Cats.Lol


People also ask

WHAT IS interface in C# net?

An interface defines a contract. Any class or struct that implements that contract must provide an implementation of the members defined in the interface. Beginning with C# 8.0, an interface may define a default implementation for members.


3 Answers

The easier solution would probably just be to have a generic interface:

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

You can then have an IFooBox<IFoo> for your basic objects, or an IFooBox<IEnhancedFoo> for the enhanced version.

like image 124
Servy Avatar answered Nov 11 '22 20:11

Servy


This type of definition will force implementers of IEnhancedFooBox to explicitly implement IFoo.Foo separately from the implementation of IEnhancedFooBox.Foo. Since this work gets tedious, I tend to reserve this for cases where a generic interface extends a non-generic interface.

For example, consider the following interfaces.

interface IFutureValue {
    object Result { get; }
}

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

It is possible to implement a general handler for all "future values" by working with IFutureValue, where code working with future values of a specific type can work with IFutureValue<T>.

like image 35
Sam Harwell Avatar answered Nov 11 '22 20:11

Sam Harwell


To answer the question,

Is this considered good practice?

The use of new is frowned upon, in general. However, as with all frowning in programming, it is a matter of judgement. If you have found a use for new that makes sense in your context, and you've ruled out other avenues like @Servy's example, then rock the new. Be prepared to defend your decision though.

like image 32
Heretic Monkey Avatar answered Nov 11 '22 20:11

Heretic Monkey