views:

951

answers:

3

I'm moving from PHP to C#.

In PHP it was simple and straightforward to use abstract classes to create a "cascading override" pattern, basically "the base class method will take care of it unless the inheriting class has a method with the same signature".

In C#, however, I just spent about 20 minutes trying out various combinations of the keywords new, virtual, abstract, and override in the base and inheriting classes until I finally got the right combination which does this simple cascading override pattern.

So even those the code below works the way I want it, these added keywords suggest to me that C# can do much more with abstract classes. I've looked up examples of these keywords and understand basically what they do, but still can't imagine a real scenario in which I would use them other than this simple "cascading override" pattern. What are some real world ways that you implement these keywords in your day-to-day programming?

code that works:

using System;

namespace TestOverride23433
{
    public class Program
    {
        static void Main(string[] args)
        {
            string[] dataTypeIdCodes = { "line", "wn" };
            for (int index = 0; index < dataTypeIdCodes.Length; index++)
            {
                DataType dataType = DataType.Create(dataTypeIdCodes[index]);
                Console.WriteLine(dataType.GetBuildItemBlock());
            }

            Console.ReadLine();
        }
    }

    public abstract class DataType
    {
        public static DataType Create(string dataTypeIdCode)
        {
            switch (dataTypeIdCode)
            {
                case "line":
                    return new DataTypeLine();
                case "wn":
                    return new DataTypeWholeNumber();
                default:
                    return null;
            }
        }

        //must be defined as virtual
        public virtual string GetBuildItemBlock()
        {
            return "GetBuildItemBlock executed in the default datatype class";
        }
    }

    public class DataTypeLine : DataType
    {
        public DataTypeLine()
        {
            Console.WriteLine("DataTypeLine just created.");
        }
    }

    public class DataTypeWholeNumber : DataType
    {
        public DataTypeWholeNumber()
        {
            Console.WriteLine("DataTypeWholeNumber just created.");
        }

        //new public override string GetBuildItemBlock()  //base method is erroneously executed
        //public override string GetBuildItemBlock() //gets error "cannot override inherited member because it is not marked virtual, abstract, or override"
        public override string GetBuildItemBlock()
        {
            return "GetBuildItemBlock executed in the WHOLENUMBER class.";
        }
    }

}
+6  A: 

virtual/override is the core polymorphism pair; sounds like you've already cracked these

abstract is like virtual, but there is no sensible base implementation; use-cases: perhaps a Stream, where it is necessary for the actual implementation to do something with the bytes. This forces the class to be abstract

new should usually be avoided; it breaks polymorphism... the most common case is to re-expose with a more specific signature / return-type (perhaps in a sealed class, since it doesn't get prettier up the chain...) - see SqlConnection.CreateCommand (vs DbConnection.CreateCommand), or (perhaps more notably) IEnumerator<T>.Current (vs IEnumerator.Current)

Marc Gravell
+2  A: 

It appears you have already figured out virtual and override from your example, so:

  • 'abstract' can also be applied on members instead of 'virtual', in which case you do not specify an implementation for the method (';' directly after the signature). This forces all concrete descendants to implement the method.

  • 'new' has nothing to do with inheritance, but can instead be used in a descendant class on a member to hide a member in the base class that has the exact same signature.

In a nutshell ;)

jerryjvl
A: 

Further to the other answers.

Overrride for when you wish to allow child classes to perform their own processing, no processing or even just call the parent class processing for a function. An override or virtual function does not have to be implemented in descendent classes.

Abstract when you don't wish to perform any processing in your base class but want that method to be implemented by any inheriting class. (Best when the inheriting class behaviour can differ drastically). If a class contains nothing but abstract methods then it is effectively an interface type. A function specified as abstract MUST be implemented in the child class (the compiler will throw an error if not).

ChrisBD