Reputation: 16874
I've been using c# since version 1, and have never seen a worthwhile use of member hiding. Do you know of any?
Upvotes: 21
Views: 971
Reputation: 660513
Imagine you are designing the runtime library for .NET 2.0. You now have generics at your disposal. You have an interface:
interface IEnumerable
{
IEnumerator GetEnumerator();
}
You wish to make a new interface
interface IEnumerable<T>
{
IEnumerator<T> GetEnumerator();
}
You now have three choices.
1) Make the generic version unrelated to the non-generic version.
2) Make the generic version extend the non-generic version. You now have two methods that differ only in return type. Change the name of GetEnumerator in the new type to GetEnumerator2(). Because that's hot. Everyone loves a good "2" method.
3) Make the generic version extend the non-generic version. Make the new and improved method hide the existing method so that its there if you need it, but hidden by default.
These are all bad choices. Which would you choose? We chose (3). Good thing that it was an option; without hiding, that option would not have been available.
Now, you might argue that this particular example of hiding was not 'worthwhile'; if that's so, what would you have done instead?
Method hiding makes it possible to expose improved interfaces without causing breakages when there are improvements to the type system.
You work at FrobCo. You produce a class Frobber that extends Blobber, which is supplied to you by the good people at BlobCo.
BlobCo has neglected to put a Frobozzle() method on Blobber, but your customers love to frobozzle frobbers, so you add a method Frobozzle() to derived class Frobber.
BlobCo realizes that their customers want to Frobozzle blobbers, so they add a non-virtual method Frobozzle() to Blobber, the base class.
Now what do you do, FrobCo employee?
1) Remove the Frobozzle method on Frobber, thereby breaking your customers who relied on your implementation. Remember, BlobCo doesn't know how to Frobozzle a Frobber; they only wrote code that knows how to Frobozzle a Blobber.
2) Whine to BlobCo that they should have made their method virtual. Hope they do something about it someday.
3) Hide their method in your derived class.
Method hiding helps mitigate the brittle base class problem.
http://blogs.msdn.com/ericlippert/archive/2008/05/21/method-hiding-apologia.aspx
Upvotes: 17
Reputation: 17216
Sometimes I make a class derived from something in the base class library, where the base class (for performance reasons) did not use a virtual function. In that case it makes sense to use 'new'. Here's one example (which matches what Marc Gravell was talking about), a strongly typed WeakReference:
public class WeakReference<T> : System.WeakReference
{
public WeakReference(T target) : base(target) { }
public WeakReference(T target, bool trackResurrection) : base(target, trackResurrection) { }
#if !WindowsCE
protected WeakReference(SerializationInfo info, StreamingContext context) : base(info, context) {}
#endif
public new T Target
{
get { return (T)base.Target; }
set { base.Target = value; }
}
}
In cases where the base class method actually IS virtual, I think Microsoft was envisioning cases where the base class is implemented by one party and the derived class is implemented by a second party. The second party adds a function "Foo", then later the first party adds another function "Foo" that actually does something different (so overriding would not be appropriate). Then, in order to maintain compatibility with third party code, the second party keeps their function named "Foo" despite the fact that it is not directly related to the base class version. In that case, the second party adds "new" to their declaration.
Upvotes: 1
Reputation: 124804
When a new version of a Type implements a publicly-visible member whose name conflicts with a name you've used in a derived Type.
To hide an inappropriate implementation in a base class from which you derive.
For example KeyedCollection<TKey, TItem>.Contains(TItem item)
is inherited from Collection<TItem>
and is therefore an O(n) operation rather than the O(1) operation that KeyedCollection<TKey, TItem>.Contains(TKey key)
usually provides.
This is arguably confusing as naive consumers may think the two are interchangeable.
So it may be appropriate to implement a "better" version:
public new bool Contains(TItem item)
{
if (item == null) throw new ArgumentNullException("item");
return this.Contains(GetKeyForItem(item));
}
Upvotes: 0
Reputation: 1533
Generally it's considered bad practice to reject an inherited member. The only time I've used it is in generated code where the new member provided a more specific type in the same class hierarchy. Same goes for explicit interface implementations.
Upvotes: 2
Reputation: 115538
We had a class that inherited from the WebControl class. When we upgraded from 3.5 to 4.0, the way that some of our attributes (mainly around onclick and javascript) changed quite radically.
We could not change how the AttributeCollection
class was handled by the WebControl
, so what we did was implement the same methods and properties of the AttributeCollection
in our custom collection and hid the AttributeCollection
property with our own.
None of the accessing code changed, and we were able to correctly implement how to handle the attributes in our classes. Now no one needs to know what we did to fix the problem. All they need to know is that they call Attributes.Add
like normal, and we fix things under the hood.
Upvotes: 5
Reputation: 888203
When making controls with rich design-time experiences, it's frequently necessary to shadow existing properties to apply attributes.
Upvotes: 2
Reputation: 1064184
Making the return type more explicit - for example SqlConnection.CreateCommand
returns a SqlCommand
, not a DbCommand
. Actually, it looks like this isn't declared new
, but that would be one of the few times I would use this; most times it is evil.
Another use: remove inherited attributes from a member.
Upvotes: 11