可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
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.