Why does the 'sealed' keyword exist in .Ne

2019-01-18 22:15发布

问题:

A large number of classes in the .Net framework are marked as 'sealed', preventing you from inheriting those classes with your own. Surely this goes against the nature of object orientation, where you can extend and redefine the behaviour of existing objects.

Is there a good reason for the existence of the 'sealed' keyword?

As an example, NotifyCollectionChangedEventArgs in Silverlight is sealed. I wanted to create my own version of ObservableCollection that supported AddRange and RemoveRange, but the Silverlight version of NCCEA doesn't provide a constructor that supports multiple items for the NewItems and OldItems properties, which are already defined as ILists. Usually, I'd just extend the class with my own variant that overrode the NewItems and OldItems properties, but in this case I can't and I can see no reason why that should be the case.

回答1:

Designing classes (or frameworks) to be extensible isn't trivial, and put simply inheritance is not the single principle of Object Oriented programming.

So sealed exists to allow the developer / designer to express and preserve those intentions. Sealing a class can also make their life easier by reducing the maintenance burden. It allows the original developer to control how the class (or framework) is extended, so they can make internal changes without worrying about breaking changes to others code.

One principle is that developers should seal any leaf classes by default. Then, when the developer creates an unsealed class intentionally, it forces them to think about extensibility.


Ref: Eric Lippert - Why Are So Many Of The Framework Classes Sealed?



回答2:

This answer from a somewhat related question I asked today might help clarify the purposes of sealing a class:

I found myself asking that same question until I started working on reusable libraries of my own. Many times you wind up with certain classes that just cannot be extended without requiring obscure or arcane sequences of calls from the implementor.

When allowing your class to be extended, you have to ask: if a developer extends my class, and passes this new class to my library, can I transparently work with this new class? Can I work properly with this new class? Is this new class really going to behave the same?

I've found that most of the time the sealed classes in the .Net Framework have certain under-the-hood requirements that you aren't aware of, and that given the current implementation cannot be safely exposed to subclasses.

Liskov Substition and Composition

Now follow that link and upvote the actual author.



回答3:

The short answer is, because Microsoft said so. The longer answer is that Microsoft has provided a mechanism to extend sealed classes, called extension methods.

In general, it's a bad idea to extend classes which which you don't have source code to. For example, you don't know what calling base method does to the internal data of the object. Yes, you can use reflector or whatever to figure it out, but in general it's much better to use composition or extension methods.

You also have to consider what inheritence actually is. It's not just a way to alter the class, it also provides polymorphism. What if you change the semantics of, say, the string class, then you pass your new string class to an object that expects a string to act in a specific way? sealed essentially enforces the contract that this object will always work the way you expect it to.



回答4:

Without digging too deeply, understand that Microsoft favors sealing a class when there are potential security, maintainability or backwards-compatibility issues that it will have to deal with downstream. For example, System.String is sealed for security and performance reasons.

In this particular case, you'd need to ask a Microsoft developer why they chose to seal that class. However, the architectural guidance literature I've been reading lately tends to favor an approach of "seal unless you know it will need to be extended." This literature tends to espouse using extension methods where possible. (I'm not saying I agree with it; I'm just saying that's what I've been reading lately.)

Even if the class weren't sealed, the properties in question might have been left not virtual, which would still leave you up the creek here.

In your specific scenario, I'd go with extension methods with your own unique names. It's about all you can do.



回答5:

While I do agree that .NET probably seals too much, it's generally to protect the integrity of an ecosystem. When one of your top priorities is to keep your overall framework/API/runtime stable, and there are somewhat fragile interdependencies between classes, it may be safest to prevent people from overriding that behavior and inadvertently destabilizing core functionality.

Though again, I do tend to feel that the .NET team seals too many classes. Sealing can sometimes be simple laziness on the part of the developer because a proper class design would be too much work.



回答6:

I would suggest that there is no good reason for sealing classes other than to protect the ignorant -err, I mean innocent. You know the old saying, "given them enough rope and they will hang themselves". Let them sway I say. Perhaps this is my C++ background, but I am quite comfortable knowing that I have the power to completely stuff things up if I am not diligent.

I tend to program by interface. The interfaces are of course public and any one is free to provide their own implementation that adheres to the contract expressed by the interface. My concrete classes that implement these interfaces tend to be a private concern and are marked internal and/or private. I don't feel that I need to seal such classes.

Where code reuse is desirable, I avoid reuse through inheritance, favouring composition and other techniques.

Sealing may also be valid on types that are considered plain-old-data types, but I'm not convinced wither way on this.



回答7:

It depends, there are classes that are intended to be just instantiated (inheritance, if exists, is used just to simplify the implementation), other classes are intended to be inherited to provide a spesific implementation.

Sealed classes have some advantages:

  • they don't have any virtual methods, so they don't have to worry about non-"exception- safe" implemented overriding methods.
  • If a class is immutable it can preserve and guarantee the immutability.

Otherwise if you want to decorate a sealed class with "comfort" methods use the extension methods (C# 3.0).



回答8:

Just because something is an object, it doesn't mean it always should be wide open for everybody to extend or redefine it's behavior.

A good analogy would be a door and a lock. A door's nature is to let people to pass through it, that's what it's built for. Yet, most doors are designed with locks that can limit the ability of people to pass through them. The decision whether a door has a lock and whether that lock is locked by default is left to the architect of the room, based on what's in the room and who should have access to it, not on the fact that it's a door.

Of course, it can be frustrating if most of the doors in particular building are locked by default, especially if there's one you really want to go through. :-) I've been there myself and I've asked the same question. The short answer is that sometimes when designing a complex framework, people tend to err a little bit on the more cautios side and have classes sealed by default, unless there is explicit scenario that requires them to be extended.



回答9:

One of the practical uses where i have found sealed keyword useful is to avoid "Fragile class issues". Here's a video which shows one of the fragile base class issues http://www.youtube.com/watch?v=xnA3RUJcyY4

Let me explain a bit in detail.

Consider the below scenario where we have a parent class called as “DbParent” with a virtual method “Insert”.

class DbParent {

    public virtual void Insert()
    {
        Console.WriteLine("Parent insert");
    }

}

Below is a simple child class with his own “Insert” implementation which is installed across various locations.

  class DbChildClass : DbParent
  {
  public void  Insert()
    {
        Console.WriteLine("Child inserts");
    }

}

Now let’s say after some months of deployment parent class developers without understanding the impact on child classes go and add a new method “Add”. This “Add” method calls the “Insert” method internally (below is the code snippet for the same).

  class DbParent
  {
  public  void Add() // Adds method with out consulting
  {
  this.Insert();
  }

  public virtual void Insert()
  {
        Console.WriteLine("Parent insert");
  }
  }

Now client programs who invoke the “Add” method by creating child class objects expect that the “Child” class “Insert” implementation should be called.

  DbChildClass o = new DbChildClass();
  o.Add();
  Console.Read();

But whoaaaa, if you run the below code you will see the parent class “Insert” is called which is not EXPECTED.

So i would go and mark the class as "Sealed" to avoid such issues.