#782 – You Can Create an Instance of a struct Without the new Keyword

Like a class, you can create an instance of a struct using the new keyword.  You can either invoke the default parameterless constructor, which initializes all fields in the struct to their default values, or you can invoke a custom constructor.

            // Method 1 - Parameterless constructor, data in struct initialized to default values
            DogCollar collar = new DogCollar();

            // Method 2 - Call custom constructor
            DogCollar collar2 = new DogCollar(10.0, 0.5);

In either case, a constructor is called.

You can also create an instance of a struct by just declaring it, without using the new operator.  The object is created, although you can’t use it until you’ve explicitly initialized all of its data members.

            // Method 3 - Just declare it
            DogCollar collar3;

            // Error - Can't use collar3 yet (use of unassigned field)
            Console.WriteLine(collar3.Length);

We need to first initialize all data members:

            // Correct - initialize first
            DogCollar collar3;
            collar3.Length = 10.0;
            collar3.Width = 5.0;
            Console.WriteLine(collar3.Length);

#723 – New Methods in Subclass May Not Be Visible in Derived Classes

You can use the new keyword in a subclass to hide a method in the parent class.  The new implementation of the method will now be used in the context of the subclass.

If you call this method in a subclass of the subclass, however, the method called depends on the accessibility of the new method.  If the new method is private, it is not visible in the lowest level class and so the original member in the base class is called.

    public class Dog
    {
        public void Bark()
        {
            Console.WriteLine("Dog: Woof");
        }
    }

    public class Terrier : Dog
    {
        public void DoBark()
        {
            Bark();
        }

        private new void Bark()
        {
            Console.WriteLine("Terrier: Woof");
        }
    }

    public class Yorkshire : Terrier
    {
        public void DoBark()
        {
            // Dog.Bark is called
            Bark();
        }
    }

 

            Dog d = new Dog();
            d.Bark();

            Terrier t = new Terrier();
            t.DoBark();

            Yorkshire y = new Yorkshire();
            y.DoBark();

#684 – Hidden Base Class Members Aren’t Really Hidden

When authoring a derived class, you can hide a member of the base class using the new keyword.  For a method, this indicates that the method in your derived class replaces the method in the base class and will be called when invoked on objects of the derived type.  (It also means that the method will not behave polymorphically).

    public class Dog
    {
        public virtual void Bark()
        {
            Console.WriteLine("Dog: Woof");
        }
    }

    public class Terrier : Dog
    {
        public new void Bark()
        {
            Console.WriteLine("Terrier: Yip yip");
        }
    }

However, if you have an instance of the derived class and cast it to the type of its base class, you’ll end up accessing the method in the base class after all.

            Terrier t = new Terrier();

            t.Bark();         // Yip yip

            ((Dog)t).Bark();  // Woof

#682 – The Real Reason for the new Keyword

Here’s a scenario that illustrates the main reason for the new keyword, allowing a method to not behave polymorphically.

Suppose you use a third-party library that defines a Dog class and you create a Terrier class in your own code that derives from Dog and defines a Speak method.  (Dog does not have a Speak method).

Now let’s say you get a new version of the Dog library in which they’ve added their own Speak method, which is virtual and which they call from the Dog constructor.

Now, when you construct a Terrier object, the Dog constructor will call Speak.  But by default, it’s Dog.Speak that’s called, rather than Terrier.Speak.  The compiler won’t just automatically make Speak behave polymorphically.

When you re-compile your code, you’ll get a warning indicating that you should make your intent explicit, by either marking Terrier.Speak as new (non-polymorphic) or as override (polymorphic).

#681 – Avoid Using the new Keyword To Hide Methods

You can use the new keyword in a derived class to hide a method in a base class, rather than overriding it.  In other words, the method in the derived class is not polymorphic, so if the method is called from a variable whose type matches the base class, the method in the base class will be called, rather than the method in the subclass.

// In Dog - public virtual void Bark()
// In Terrier : Dog - public new void Bark()

Dog d = new Terrier("Bob");
d.Bark();   // Dog.Bark called, rather than Terrier.Bark

If a Terrier really is-a type of Dog, then this lack of polymorphism on the Bark method doesn’t really make sense.  If you wanted to add a method to Terrier that was really something entirely new, you should give it a new name to avoid confusion, rather than using the new keyword.

#680 – Virtual Modifier Combinations

Below is a chart showing all of the possible combinations for the virtual, override, new and sealed modifiers, which dictate polymorphic behavior of inherited members.

The chart shows the allowed combinations for an inheritance tree consisting of three classes–DogTerrier (which inherits from Dog) and Yorkshire (which inherits from Terrier).  It’s assumed that there is a member in each class, e.g. a Bark method.  This chart then shows all the possible combinations of modifiers for that member, within each of the three classes.

For example, you could:

  • Declare Dog.Bark as virtual
  • Declare Terrier.Bark as override
  • Declare Yorkshire.Bark as new

#679 – Hide An Inherited Method with A Virtual Method

You typically hide an inherited method using the new keyword, indicating that the method should not behave polymorphically.  If you later inherit this method in a subclass, you won’t be able to override the method marked as new.

For example:

  • virtual Dog.Bark  – can override
  • new Terrier.Bark – hides Dog.Bark
  • new Yorkshire.Bark – must hide, can’t override

However, if you want to hide an inherited method, but still allow overriding in a subclass, you can use the virtual new combination:

  • virtual Dog.Bark – can override
  • virtual new Terrier.Bark – hides Dog.Bark, but allows overriding
  • override Yorkshire.Bark – overrides Terrier.Bark

In this case, Terrier and Yorkshire objects referenced by variables of type Dog will not behave polymorphically.  But a Yorkshire object referenced by a Terrier variable will behave polymorphically.