#1,164 – A Sealed Event Cannot Be Overridden

As with a method, you can use the sealed keyword when overriding a virtual event to indicate that child classes cannot override the event being defined.

When you override an event, you create a virtual event that behaves polymorphically.  The base class defines the event using the virtual keyword and you define the event in your child class using the override keyword.

When you use the override keyword, your event can itself be overridden in a child class.

If you want to override an event, but prevent any derived classes from overriding your implementation, you can use the sealed keyword to indicate that a child class must use the new keyword, rather than overriding your event.

    public class Dog
    {
        public string Name { get; set; }

        public Dog(string name)
        {
            Name = name;
        }

        public virtual event EventHandler<string> Barked;
    }

    public class Terrier : Dog
    {
        public Terrier(string name) : base(name) { }

        private EventHandler<string> terrierBarked;
        public sealed override event EventHandler<string> Barked
        {
            add
            {
                terrierBarked += value;
                // Special Terrier.Barked event logic here
            }
            remove
            {
                terrierBarked -= value;
            }
        }
    }

    public class JackRussell : Terrier
    {
        public JackRussell(string name) : base(name) { }

        public new event EventHandler<string> Barked;
    }
Advertisement

#798 – You Can’t Override Accessors that Are Not Accessible

When you override a virtual property in a child class, you must replicate the accessibility of the accessors in the parent’s class.

However, if one of the accessors has been made inaccessible to the child class, you’ll be able to override the property itself, but not that accessor.

In the example below, we override the Description property, including the get accessor.  However, if we try to include the set accessor in the overridden property, we get a compile-time error because the set accessor is not accessible to the child class.

    public class Animal
    {
        protected string description;
        public virtual string Description
        {
            get { return string.Format("Animal: {0}",description); }

            private set
            {
                if (value != description)
                    description = value;
            }
        }
    }
    public class Dog : Animal
    {
        public override string Description
        {
            get { return string.Format("Dog: {0}", description); }

            private set
            {
                if (value != description)
                    description = value;
            }
        }
    }

798-001

#770 – Use Intellisense to Get List of Methods to Override

In a derived class, you can override a member of the base class if it’s declared as virtual.  In Visual Studio, the Intellisense feature can help you to discover the methods that can be overridden.

Suppose that we have the following definition for Dog:

    public class Dog
    {
        public virtual string Prop1 { get; set; }
        public string Prop2 { get; set; }

        public virtual void Method1()
        {
            Console.WriteLine("Dog.Method1");
        }

        public void Method2()
        {
            Console.WriteLine("Dog.Method2");
        }
    }

Now when we are adding code to a child class of Dog, we can just enter the keyword override, followed by a space, to see a list of candidate members that can be overridden.

770-001

To add the code for one of these members, just use the down arrow to select the method and then press TAB.  The body of the method will be generated for you.

770-002

#769 – Pattern – Call a Base Class Method When You Override It

You can call a method in a class’ base class using the base keyword. You can do this from anywhere within the child class, but  it’s a common pattern to call the base class method when you override it.  This allows you to extend the behavior of that method.

Here’s an example.

    public class Dog
    {
        public string Name { get; set; }
        public int Age { get; set; }

        public Dog(string name, int age)
        {
            Name = name;
            Age = age;
        }

        public virtual void DumpInfo()
        {
            Console.WriteLine(string.Format("Dog {0} is {1} years old", Name, Age));
        }
    }

    public class Terrier : Dog
    {
        public double GrowlFactor { get; set; }

        public Terrier(string name, int age, double growlFactor)
            : base(name, age)
        {
            GrowlFactor = growlFactor;
        }

        public override void DumpInfo()
        {
            base.DumpInfo();

            Console.WriteLine(string.Format("  GrowlFactor is {0}", GrowlFactor));
        }
    }

 

            Terrier t = new Terrier("Jack", 17, 9.9);
            t.DumpInfo();

769-001

#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.

 

#678 – A Sealed Method Cannot Be Overridden

When you override a method, you create a virtual method that behaves polymorphically.  The base class defines the method using the virtual keyword and you define the method in your child class using the override keyword.

When you use the override keyword, your method can itself be overridden in a child class.

If you want to override a method in a base class, but also prevent any derived classes from overriding your method, you can use the sealed keyword to indicate that a child class must use the new keyword, rather than overriding your method.

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

    public class Terrier : Dog
    {
        public sealed override void Bark()
        {
            Console.WriteLine("  Terrier is barking");
        }
    }

    public class JRT : Terrier
    {
        public new void Bark()
        {
            Console.WriteLine("  JRT is barking");
        }
    }

#677 – Method Marked with new Modifier Cannot Be Overridden

You can use the new modifier on a method to indicate that the method should hide a method of the same name in a base class.  In other words, the method does not behave polymorphically.

If you’ve marked a method as new in a class, that method is not virtual and can not be overridden in a derived class.

In the example below, the Dog class marks Bark as virtual, indicating that it can be overridden.  The Terrier class marks Bark as new, indicating that it does not override Dog.Bark–and that it cannot be overridden.  JRT can therefore not override Bark.

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

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

    public class JRT : Terrier
    {
        public new void Bark()
        {
            Console.WriteLine("  JRT is barking");
        }
    }