11

I was reading somewhere about how to handle the issue of wanting to extend a sealed class in the .NET Framework library.

This is often a common and useful task to do, so it got me thinking, in this case, what solutions are there? I believe there was a "method" demonstrated to extend a sealed class in the article I read, but I cannot remember now (it wasn't extension methods).

Is there any other way? Thanks

GurdeepS
  • 65,107
  • 109
  • 251
  • 387
  • highly related: http://stackoverflow.com/questions/554145/liskov-substition-and-composition – cregox Sep 04 '13 at 20:05

7 Answers7

9

There is 'fake' inheritance. That is, you implement the base class and any interfaces the other class implements:

// Given
sealed class SealedClass : BaseClass, IDoSomething { }

// Create
class MyNewClass : BaseClass, IDoSomething { }

You then have a private member, I usually call it _backing, thus:

class MyNewClass : BaseClass, IDoSomething
{
   SealedClass _backing = new SealedClass();
}

This obviously won't work for methods with signatures such as:

void NoRefactoringPlease(SealedClass parameter) { }

If the class you want to extend inherits from ContextBoundObject at some point, take a look at this article. The first half is COM, the second .Net. It explains how you can proxy methods.

Other than that, I can't think of anything.

Jonathan C Dickinson
  • 7,181
  • 4
  • 35
  • 46
  • Because of this wrapping-style inheritance, I don't really understand the point of "sealed" classes - they clearly don't *prevent* you from, in practice, extending a class. The inventors of sealed classes must have known this, so what's the point in them really? To 'encourage' people not to extend a class? To make it 'more of a pain' to extend a class? Why not just say in the documentation, "this class should not be inherited"? – Jez Jan 04 '13 at 09:27
  • @Jez If you're going to "just say in the docs, this class should not be inherited" I prefer setting it as sealed and not rely on docs. But that's really not its usage. It's nothing trivial, tho, I recommend you do some research. As I'm reading and learning about `sealed` I'm still clueless on [why to use it](http://geekswithblogs.net/gmamaladze/archive/2010/02/01/sealed_keyword.aspx), but too many people think classes should be sealed by default and then have the keyword `unsealed` instead. – cregox May 14 '13 at 21:19
  • 1
    @Cawas I don't really like the mentality of `sealed`, which seems to be not to trust the developer. What if the developer reasonably wants to extend a class? This keywords just makes it more of a pain in the ass. It's a bug, not a feature, and I haven't seen any convincing argument otherwise. Again, I don't mind "encouraging" someone not to extend a class, but ultimately, the developer should be able to force the issue and not be stopped (or forced to use wrapping, breaking proper OOP) by a keyword. – Jez May 15 '13 at 10:26
  • @Jez after more reading and discussing and considering, I have to agree. I could see only few good reasons for `sealed` to exist, but none that justify its existence and the trouble it causes. And specially nothing that justify so many people advocating it. All that being said I still think there's no point in "just say in the docs" if you can enforce it in the code. And I'm still hoping someone will give a good practical example on [why it even exists (unlike this)](http://stackoverflow.com/questions/554894/why-does-the-sealed-keyword-exist-in-net). I think there is a good reason somewhere. – cregox May 15 '13 at 11:01
  • @Jez here is my final world on sealed classes: [don't *ever* seal a class unless you *know* you'll have support issues with your clients.](http://programmers.stackexchange.com/a/210481/4261) – cregox Sep 04 '13 at 20:01
  • And @Jonathan to handle a sealed class, there's also [composition](http://stackoverflow.com/a/891820/274502). – cregox Sep 04 '13 at 20:04
  • A good compromise might be that instead of preventing inheritance completely, a sealed class needs an extra keyword to be extended. Kind of like unsafe, telling the developer "Hey, you probably shouldn't do this". – blenderfreaky Jul 11 '19 at 17:14
6

this method may have already been mentioned above by it's formal name, but i don't know it's formal name, so here it is. This example "extends" the TextBox class (example in VB). I believe an advantage of this method is that you do not need to explicitly code or expose built-in members. Hope this is relevant:

VB Class Module "MyTextBox":

public Base as TextBox, CustomProperty as Integer

Private Sub Init(newTextBox as TextBox)
    Set Base = newTextBox
End Sub

public Property Get CustomProperty2() As String
    CustomProperty2 = "Something special"
End Property

To call the code, you might say:

Dim MyBox as New MyTextBox
MyBox.Init MyForm.TextBox3

from here you have access to all built-in members, plus your custom members.

Debug.Print MyBox.Base.Text
MyBox.CustomProperty = 44

For extra polish, you can make Base the default property of the class, and then you can leave out "Base" when you call properties of the Base class. You call Base members like this:

Debug.Print MyBox().Text
MyBox().Text = "Hello World"

VBA Demo

johny why
  • 2,047
  • 7
  • 27
  • 52
6

Extension methods is one way, the alternative being the Adapter Pattern. Whereby you write a class that delegates some calls to the sealed one you want to extend, and adds others. It also means that you can adapt the interface completely into something that your app would find more appropriate.

Neil Barnwell
  • 41,080
  • 29
  • 148
  • 220
2

Maybe use the Decorator pattern?

Other than extension methods, this is the only sensible technique I can think of.

LukeH
  • 263,068
  • 57
  • 365
  • 409
2

No, you can't extend a sealed class in any legitimate way.

TypeMock allows you to mock sealed classes, but I doubt that they'd encourage you to use the same technique for production code.

If a type has been sealed, that means the class designer has not designed it for inheritance. Using it for inheritance at that point may well cause you lots of pain, either now or when the implementation is changed at a later date.

Prefer composition to inheritance - it's a lot more robust, in my experience. See item 16 in "Effective Java (2nd edition)" for more on this.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • Thanks for the warning of the dangers and direction (book recommendation). – GurdeepS Mar 18 '09 at 09:50
  • 1
    Effective Java is an awesome book, even for C# developers. Not all of it is relevant to C#, but it's extremely well written. – Jon Skeet Mar 18 '09 at 09:54
  • 1
    I would not recommend using TypeMock outside of your test environment. – Brian Rasmussen Mar 18 '09 at 10:12
  • Composition: http://stackoverflow.com/questions/554145/liskov-substition-and-composition/554192#554192 - But could you elaborate more unsealed classes can generate *lots* of pain or even just give a good example? – cregox May 14 '13 at 22:35
  • @Cawas: I don't have time to find a great example now, although I've seen a few recently. http://stackoverflow.com/questions/16548762 gives an example of the kind of problem that inheritance can introduce though - how implementation details start having to be documented in order to avoid misbehaviour. – Jon Skeet May 14 '13 at 22:37
  • @JonSkeet thanks for the amazingly prompt answer and cool link, but I couldn't make any use of it for understanding `sealed`. I did more research tho, and came up to [this](http://stackoverflow.com/a/8434189/274502): it seems like sealing a class only truly makes sense if you're developing a framework or anything meant to be extended by at least another unknown developer, outside of your scope. I never did that by any extension, so maybe that's why I'm having difficulty to grasp its concept, and explain why it's so hard to give a good example. Am I on the right path? – cregox May 15 '13 at 11:46
  • @Cawas: Well it depends on how far you want to take things. If you're absolutely sure you will always *personally* know everyone who comes into contact with your code, then it mitigates some of the risks. But that means even within a medium-sized company, it's really better to seal the class IMO. I like Josh Bloch's approach to this: "design for inheritance or prohibit it" - designing for inheritance is costly, and the cost of *failing* to design for it (but also failing to prohibit it) can also be costly, in terms of very messy code. – Jon Skeet May 15 '13 at 12:05
  • Ok, so I think I understand what the conservative line of thought tell us about sealing stuff: Helps preventing potential issues when we greatly (to me, more than 5 people coding same thing is "greatly") expand the code, thus code meant to be re-used should pay way more attention than developers currently do to `sealed`. Maybe I just still don't see [how inheritance design could be so costly](http://stackoverflow.com/questions/268251/why-seal-a-class/268287#268287)... I'll let time take care of this. :-) – cregox May 15 '13 at 14:10
  • I'm back at this subject, and still couldn't figure it out... Can you maybe kindly [help me out again](http://programmers.stackexchange.com/questions/210461/one-good-reason-to-use-sealed), Sir? [bows down in respective gesture] – cregox Sep 04 '13 at 17:37
2

The only way I know to "extend" a sealed class without extension methods is by wrapping it. For example:

class SuperString
{
    private String _innerString;

    public SuperString(String innerString)
    {
        _innerString = innerString;
    }

    public int ToInt() 
    {
        return int.Parse(_innerString);
    }
}

You'd need to expose all of the same methods/properties as the string class.

Some frameworks allow you to extend existing objects. In WPF, see Dependency Properties. For Windows Forms, see IExtenderProvider.

Paul Stovell
  • 32,377
  • 16
  • 80
  • 108
0

How about extension methods? You can "add" additional methods that way, without having to deal with the inheritance restriction.

eglasius
  • 35,831
  • 5
  • 65
  • 110