1

Curious situation:

public class MyTextBox : TextBox
{
    // I want use the same height for all MyTextBoxes
    public new static int Height;
}

public Form1()
{
    InitializeComponent();

    MyTextBox mtb1 = new MyTextBox();
    MyTextBox mtb2 = new MyTextBox();

    mtb1.Multiline = true;
    mtb2.Multiline = true;

    mtb1.Location = new Point(50, 100);
    mtb2.Location = new Point(200, 100);

    mtb1.Size = new Size(50, 50);
    mtb2.Size = new Size(150, 150);

    Controls.Add(mtb1);
    Controls.Add(mtb2);

    mtb1.Text = mtb1.Height;
    mtb2.Text = mtb2.Height;
    // Error 1 Member 'WindowsFormsApplication9.MyTextBox.Height'
    // cannot be accessed with an instance reference;
    // qualify it with a type name instead
}

The same thing in VB.NET

Public Class MyTextBox
    Inherits TextBox
    Public Shared Shadows Height As Integer
End Class

mtb1.Text = mtb1.Height ' Text will be "0" '
'Warning 1   Access of shared member, constant member, enum member or nested '
' type through an instance; qualifying expression will not be evaluated.

Questions:

==

  1. Couldn't this method be used to hide the public members in the inherited classes? Sometimes this can be useful...
  2. How can I use same Height for all members?
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
serhio
  • 28,010
  • 62
  • 221
  • 374

1 Answers1

1

When would it be useful? I really don't think it's a good idea to hide members in this way. It's just going to cause a maintenance nightmare - when you see "Height" you can't easily tell which member it's really referring to.

IMO, "new" should only be used as a last act of desperation, usually if a base class has introduced a member which clashes with one of your existing ones. It shouldn't be used as a way of deliberately avoiding normal OO design principles.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • ok, what about the same height for all textboxes? Or I should rename the field? – serhio Feb 03 '10 at 10:33
  • 2
    @serhio: Definitely rename the field - if indeed you need a field in the first place. – Jon Skeet Feb 03 '10 at 10:37
  • @Jon Skeet: What if the base class provides a protected member which should not be made available to descendants of a particular derived class (e.g. MemberwiseClone)? It would seem better to hide the protected member by shadowing it with something that should obviously not be used (e.g. an WriteOnly property of an enumeration type DontTryThis whose only defined value is DontTryThis.NoReallyDont) than leave it available allow it to be wrongfully called. A keyword specifically to simply hide the inherited method might be nicer, but I don't know of one in vb.net or C#. – supercat Dec 02 '10 at 21:28
  • @supercat: If the base class provides a protected member, that *should* be visible to all derived classes. Otherwise it's breaking Liskov's Substitution Principle. Basically it's poor design - don't put a sticking plaster over it with "new". – Jon Skeet Dec 02 '10 at 21:31
  • @Jon Skeet: The LSP is important for public members of a class because a derived class 'foo' which derives from 'bar' might be passed to some code that expects a 'bar'. If a 'foo' could not be used in place of a 'bar', such code would break. Such polymorphism isn't an issue with protected methods. If class 'foo' inherits from 'bar', the base of a foo object will be a 'bar'. Period. There's no way some other class will be inherited from 'bar' and somehow become the base of foo. The fact that bases cannot be substituted is a big part of the reason for having protected members in the first place. – supercat Dec 02 '10 at 23:48
  • @Jon Skeet: Consider MemberwiseClone. If using MemberwiseClone on an object of some class would create an invalid new object, corrupt the original object, or both, what code would be broken by obscuring the MemberwiseClone method? What badness would it cause, or what goodness would it prevent? If no good can come from accessing a parent's protected member from a sub-derived class, why allow such access? – supercat Dec 02 '10 at 23:54
  • @supercat: It's the same deal of saying, "I'm like this base class - but not really." It stinks of bad design to me. It does suggest to me that MemberwiseClone possibly wasn't a great idea in the first place, but that's a different matter... – Jon Skeet Dec 03 '10 at 00:04
  • @Jon Skeet: To be sure, it's possible that a parent class might expect to usefully employ a protected member of a derived class, but shadowing wouldn't affect that. Of course, there's no guarantee that such an access wouldn't break things, but the proper solution to that problem is for parents not to access protected members of other object instances. If one disallowed protected members which didn't follow the LSP, many useful things like cloning would be impossible. – supercat Dec 03 '10 at 00:04
  • @Jon Skeet: MemberwiseClone is vital. It would be almost impossible to construct a robust framework for cloning mutable objects without it. Think of public methods as saying: "Hey everyone--here's what you'll get from me or any of my descendants". Protected methods say, "If you derive from me, here's what you get--if you want any promises about my descendents, you should derive from them." If one enforced the LSP on protected methods, no non-trivial class could have some derived types support cloning and others not. – supercat Dec 03 '10 at 00:10
  • @Jon Skeet: On the other hand, if one has a protected overridable BaseClone method (which at the lowest level would call MemberwiseClone), a class can say "Psst. I don't mind if you clone me, but I can't promise that derived types will be clonable. If you want a clonable version of me, derive one with a public Clone method." If you want to derive from me but cloning would break you, seal off the protected method. – supercat Dec 03 '10 at 00:12
  • @supercat: I'm going to bed now - too tired to discuss this at the moment. Will try to pick it up in the morning. – Jon Skeet Dec 03 '10 at 00:21
  • @supercat: I'm still uncomfortable with the idea of "removing" protected members, but I'm finding it hard to articulate the exact reasons - it just *feels* wrong, and that's not really a good argument. With regard to cloning, I agree it's important (although I personally try to avoid cloning wherever possible) but I wouldn't want the *language* to have to bend around this one special case. – Jon Skeet Dec 03 '10 at 09:28
  • @Jon Skeet: Cloning is a convenient example of a feature that a derived class may or may not want to support, but it's hardly unique. A class may have protected mutator methods, which should be used by mutable subclasses, but hidden in immutable ones (while it's rare for immutable classes to allow inheritance, there are cases where it may be useful; certainly an immutable class should not expose protected mutators). – supercat Dec 03 '10 at 17:17
  • @supercat: A class which can be derived from can never claim to be immutable. It can claim not to allow mutation of its own data, but someone can always create a subclass which has its own data which can be mutated. Again, I'd say such a design is problematic. – Jon Skeet Dec 03 '10 at 17:23
  • @Jon Skeet: Think of a base class as a master blueprint for a somewhat generic house with some features unspecified. Such a blueprint might include both an oil fill pipe and a gas line, to allow for the installation of either an oil or a gas furnace. If one derives from that a plan for a house with a particular gas furnace, one should NOT include the oil fill pipe. It may be important to have the oil fill pipe in the master blueprint to ensure that plans could be usefully adapted from the master to build an oil-heated house, but that does not imply that all derived plans should include it! – supercat Dec 03 '10 at 17:25
  • @supercat: I'm finding it hard to convert that into a good piece of software design, to be honest. I think we may have to agree to disagree. – Jon Skeet Dec 03 '10 at 17:26
  • @Jon Skeet: If a plan seals the Equals and GetHashCode functions, and requires that any derived classes must pass to the constructor (perhaps in some kind of list) any data they want to have included, it would be somewhat difficult for a derived class to violate the LSP. The only way I could see for an LSP violation would be if a dictionary were created for the base class using EqualityComparer(of BaseClass).Default, rather than using a comparer that explicitly calls a non-overridable Equals method. – supercat Dec 03 '10 at 17:32
  • @Jon Skeet: The main use I would see for such inheritance would be to derived classes which would enforce certain invariants regarding the stored data. For example, an ImmutableSquare class which inherits from ImmutableRectangle, and has a constructor that ensures that the sides of the ImmutableRectangle are equal. A method that could only deal with squares could take an ImmutableSquare argument, but could pass it to other code that expects ImmutableRectangle. – supercat Dec 03 '10 at 17:39
  • @Jon Skeet: If you don't like hiding protected members, what is the alternative? Exposing protected members which, if used, will break the class? If one forbids the derivation of any class which can't usefully support all its parent's protected methods, many useful class designs will become essentially impossible. – supercat Dec 03 '10 at 17:48