.NET for Visual FoxPro Developers

Chapter 5
Object Orientation in C# and Visual Basic .NET

With the release of Visual FoxPro 3.0, FoxPro became object-oriented. For those of you who have already made the leap to object-oriented programming, you know how difficult the transition can be. Fortunately, once you’ve learned OOP in VFP, it’s easy to learn the basics of OOP in .NET. This chapter shows how different object-oriented features are implemented in C# and Visual Basic .NET, while providing a comparison to Visual FoxPro’s object-orientation.

By its very nature, this chapter is one of the more controversial in this book. The two previous chapters were devoted to the basics of C# and Visual Basic .NET syntax, but this chapter moves into the meatier topic of object-orientation, providing a side-by-side comparison of the two languages. Many of you may use the information in these chapters to decide which .NET language to choose—and choice of language is often a religious issue!

As in the previous chapters, I’ll point out the differences in C# and VB .NET and offer some editorial comments on the approach I think is better. Although both languages compile down to the same intermediate language (MSIL), they implement .NET’s object-oriented features a little differently—and in some cases, one language has object-oriented features not available in the other language. Throughout this chapter, I’ll draw comparisons to Visual FoxPro’s object-oriented features so you can leverage your existing knowledge of OOP.

Where do you put your code?

Visual FoxPro allows you to place code in class methods, in functions or procedures stored in PRG files, or as procedural code stored in PRG files.

In contrast, all code in C# must be placed in classes. This is similar to other pure object-oriented programming languages, such as Java and SmallTalk that impose more discipline
on developers.

Visual Basic .NET takes an approach more like Visual FoxPro, in allowing you to place code and variables in either classes or modules. Similar to a class, a module is derived from the System.Object class and used to encapsulate items contained within it. The main differences between a class and a module are a class can be instantiated and implement interfaces, but a module cannot.

Another difference is in referencing members of a class, you must specify the name of the class followed by the member (for example, Customer.GetCreditLimit). In contrast, members declared in a module are like global variables and functions accessed from anywhere within your application. By default, members of a module are shared  (For details, see the “Instance and static (Shared) members” section later in this chapter). You can compare placing code in modules to creating global variables, functions, and procedures in a Visual FoxPro PRG.

Are modules a “good thing” or a “bad thing”? I think the answer to this is subjective. Personally, I tend to prefer a more “pure” object-oriented approach, because I believe it promotes better programming practices. However, you may prefer the convenience of being able to create standalone functions and procedures in a Visual Basic .NET module.

Classes

At the very heart of any object-oriented language are classes. I’ll begin by discussing the mechanics of where and how you define classes.

In Visual FoxPro, you define classes visually in VCX files or manually in PRG files. Defining classes in C# and VB .NET takes an approach somewhere in between. In these languages, you can place class definitions in source files (either .cs or .vb files), which are similar to Visual FoxPro’s PRG files. However, Visual Studio .NET lets you easily navigate to a particular class and a specific method in a source code file using the class and member combo boxes at the top of the code-editing window.

The class combo box (Figure 1) contains a list of all classes defined in a source code file. Selecting a class from this combo box takes you to the class definition in the source code.

Figure 1. The class combo box, at the top left of the code-editing window, contains a list of all classes defined in the source code file.

The member combo box (Figure 2) contains a list of all members defined for the currently selected class. Selecting a member from this combo box takes you to the member in the source code file.

Figure 2. The member combo box at the top right of the code-editing window contains a list of all members for the currently selected class.

As you manually page or arrow up/down in the source code file, the selected items in these boxes change to reflect your current location in the source code—a nice feature.

Defining classes

In Chapter 3, “Introduction to C#”, and Chapter 4, “Introduction to Visual Basic .NET”, you learned the basics of defining classes. In this chapter I’ll review some of that information and expand on it.

Here’s an example of the most simple class definition in C#:

public class SimpleClass

{

}

And in VB .NET:

Public Class SimpleClass

 

End Class

In both cases, this code defines a class named “SimpleClass”. The public keyword is an access modifier specifying the visibility of the class. If you don’t specify an access modifier, the visibility defaults to “internal” for C# and the equivalent “friend” for VB .NET. Table 1 lists the access modifiers that apply to classes.

Table 1. C# and VB .NET class access modifiers

C#
Access modifier

VB .NET
Access modifier

Description

public

public

Indicates no restrictions for accessing the class.

internal

friend

Indicates the class is only accessible from code within the same assembly where the class is defined.

 

Defining fields (member variables)

As discussed in Chapter 3, “Introduction to C#”, variables declared at the class level are known as fields, and as discussed in Chapter 4, “Introduction to Visual Basic .NET”, they are known as member variables in VB .NET. I don’t want to skip mentioning this here, but check out the corresponding chapter for details on each of these.

Defining properties

C# and Visual Basic .NET properties are similar to Visual FoxPro properties with associated access and assign methods. They are implemented as get and set accessor methods containing any code you want. Here is an example of a property used to retrieve and store the value of a private field (member variable in VB .NET).


In C#:

private int age = 99;

 

public int Age

{

  get

  {

       return this.age;

  }

  set

  {

       this.age = value;

       }

  }

And in Visual Basic .NET:

Private _age As Integer = 99

 

Public Property Age() As Integer

    Get

        Return _age

    End Get

    Set(ByVal Value As Integer)

        _age = Value

    End Set

End Property

In this code, the property has a get method used to retrieve the value from a private field, and a set method that stores a value to the private field. Notice the C# code sample takes advantage of C#’s case sensitivity, by naming the private field age and the property Age. Because VB .NET isn’t case sensitive, you need to give any associated member variable a different name than the property.

Text Box: ¥

It is not required for a property to have an associated field (member variable), although they often do. For example, rather than getting and setting the value of a field, code within a property might read and write data instead.

Notice in the C# sample code, the set method uses an intrinsic parameter named value. When client code saves a value to a property, it is stored in this intrinsic value variable. In contrast, although the Set method in the VB .NET sample code explicitly declares a variable named Value, you are allowed to change the name of this variable (although I can’t think of a compelling reason to do so).

Read-only and write-only properties

In C#, if you want to create a read-only property, all you have to do is leave out the set accessor method. For example:


private int height;

 

public int Height

{

  get

  {

       return this.height;

  }

}

You do the same thing in Visual Basic .NET, but you must also add the ReadOnly keyword to the property definition:

Private _height As Integer

 

Public ReadOnly Property Height() As Integer

    Get

        Return Me._height

    End Get

End Property

If you want to create a write-only property in C#, just leave out the get accessor method. You do the same thing in Visual Basic .NET, but you must also add the WriteOnly keyword to the property definition.

Defining methods

A class doesn’t do much without methods. Here’s an example of a simple method declaration
in C#:

public void SimpleMethod()

{

}

And in Visual Basic .NET:

Public Sub SimpleMethod()

 

End Sub

This code defines a method named “SimpleMethod” that returns nothing (void, in C#). Both C# and VB .NET require parentheses after the name of the method. As shown in the next section, these parentheses contain a list of parameters passed to the method. In this case, even though there are no parameters, you must still add the parentheses as a placeholder.

Here’s an example of a C# method that returns a boolean value:

public bool SimpleMethodBool()

{

  return true;

}

This is exactly the same as the previous C# method declaration, except I specified the return value is boolean rather than void, and I added a line of code that returns a boolean value. This is extremely consistent syntax.

Now here’s the same method in Visual Basic .NET:

Public Function SimpleMethodBool() As Boolean

  Return True

End Function

Notice the method is declared as a function rather than a subroutine (Sub) and has an additional As clause specifying the type of the return value. What’s going on here?

In VB .NET, to specify a method return nothing, you must declare it as a subroutine (Sub). If a method returns a value, you must declare it as a Function and use the As clause to specify the return value type.

In all the methods shown above, the public keyword is an access modifier specifying the class visibility. Table 2 lists all access modifiers for C# and VB .NET members.

Table 2. C# and VB .NET class member access modifiers

C#
Access modifier

VB .NET
Access modifier

Description

public

Public

No restrictions for accessing the member.

protected

Protected

The member is only accessible from within the class or from classes derived from the class.

internal

Friend

The member is only accessible from code within the assembly where the member is defined.

protected internal

Protected Friend

The member is only accessible from within the class or from code within the assembly where the member is defined.

private

Private

The member is only accessible within the containing class.

Specifying method parameters

There are a few different kinds of method parameters in C# and VB .NET (Table 3) described in the following sections.

Table 3. C# and VB .NET method parameters

C# parameter keywords

VB .NET
Access modifier

Description

(no keyword needed)

ByVal

Value parameter—the default for C# and VB .NET

reference

ByRef

Reference parameter

params

ParamArray

Parameter array

out

Not required

Output parameter

n/a

Optional

Optional parameter

 


Value parameters

Just as in Visual FoxPro, the default parameter type in both C# and Visual Basic .NET is a value parameter. In practical terms, if the method you call changes the value of the parameter, the value is not changed in the calling method. Here’s an example of a method with a value parameter in C#:

public void ValueParam(int age)

{

  age++;

}

And in Visual Basic .NET:

Public Sub ValueParam(ByVal age As Integer)

    age = age + 1

End Sub

In C#, if you don’t specify otherwise, the parameter is passed by value. In VB .NET, if you don’t specify the kind of parameter, Visual Studio .NET automatically inserts the ByVal keyword for you.

Reference parameters

When you pass a parameter by reference, if the method changes its value, the value is also changed in the calling method. Here’s an example using a reference parameter in C#:

public void ReferenceParam(ref int age)

{

  age++;

}

And in Visual Basic .NET:

Public Sub ReferenceParam(ByRef age As Integer)

    age += 1

End Sub

In C#, if a method accepts a reference parameter, you must specify in the method call that you are passing the value by reference:

PtDemo.ReferenceParam(ref age);

In Visual Basic .NET, you don’t have to specify you’re passing the value by reference:

PtDemo.ReferenceParam(Age)


Array parameters

You can pass a variable number of parameters to a C# or VB .NET method by declaring an array parameter. Within the method body, you can use a foreach loop to access all items in the passed array.

In C#:

public void ArrayParam(params int[] ages)

{

  string AgeMsg = "";

 

  foreach (int i in ages)

  {

       AgeMsg += i + ": ";

  }

 

  MessageBox.Show("Ages: " + AgeMsg, "Array Parameter demo");

}

In Visual Basic .NET:

Public Sub ArrayParam(ByVal ParamArray ages() As Integer)

    Dim AgeMsg As String = ""

 

    Dim i As Integer

    For Each i In ages

        AgeMsg += i.ToString() & ": "

    Next i

 

    MessageBox.Show("Ages: " & AgeMsg, "Array Parameter demo")

End Sub 'ArrayParam

Output parameters

C# has output parameters—a parameter type not available in Visual Basic .NET. An output parameter is similar to a reference parameter, but it allows you to pass a variable to a method without first specifying an initial value. If you remember from Chapter 3, “Introduction to C#”, in an effort to encourage good programming practices, C# requires you to specify a value for all variables before using them. Output parameters are the one exception to the rule. To demonstrate, here’s a C# method that declares a single output parameter:

public void OutParam(out int age)

{

  age = 39;

}

And here’s an example of code calling this method:

int JackBennysAge;

PtDemo.OutParam(out JackBennysAge);

Notice this code declares the variable JackBennysAge, but never stores an initial value. So why aren’t output parameters available in VB .NET? Because VB .NET does not require you to initialize variables (although it’s a good idea to specify initial values anyway!).

Optional parameters

Visual Basic .NET has a type of parameter not available in C#—optional parameters. Optional parameters provide a way to specify a particular parameter that is not mandatory. When declaring an optional parameter, you must specify a default value in case the caller doesn’t pass a value for the optional parameter. For example, here’s a VB .NET method that declares a single optional parameter with a default value of 50:

Public Sub OptionalParam(Optional ByVal age As Integer = 50)

At first, optional parameters might seem like a great feature. However, you should probably avoid using them! One reason is C# does not recognize optional parameters—it sees them as mandatory, just like every other parameter. This is an important consideration if you anticipate C# clients may be accessing your code. Optional parameters can also introduce problems if you ever decide to change the default value of the optional parameter. For details, see the MSDN article “Exploiting New Language Features of Visual Basic .NET, Part 2” (http://msdn.microsoft.com/msdnmag/issues/01/08/instincts/instincts0108.asp).

In reality, avoiding optional parameters is not a real loss. You can actually accomplish the same thing by means of overloaded methods.

Overloaded methods

In Visual FoxPro, all class methods must have unique names. You may be surprised to learn this is not true in C# or Visual Basic .NET. Both languages allow you to create multiple methods with the same name—as long as the number and type of parameters is different. For example, the following code defines a class with two methods, both named “DisplayMessage”.

In C#:

  public class OverloadedMethodsDemo

  {

       public void DisplayMessage(string message, string caption)

       {

          MessageBox.Show(message, caption);

       }

 

       public void DisplayMessage(string message)

       {

          this.DisplayMessage(message, "Application Message");

       }

  }

And in Visual Basic .NET:

Public Class OverloadedMethodsDemo

 

    Public Overloads Sub DisplayMessage(ByVal message As String, _

        ByVal caption As String)

        MessageBox.Show(message, caption)

    End Sub 'DisplayMessage

 

    Public Overloads Sub DisplayMessage(ByVal message As String)

        Me.DisplayMessage(message, "Application Message")

    End Sub 'DisplayMessage

 

End Class 'OverloadedMethodsDemo

Although these methods have the same name, they have a different signature. In object-oriented terminology, the word signature refers to the type and order of a method’s parameters. In this case, the first overload of the DisplayMessage method accepts two string parameters—one named “message” and the other named “caption”. The second overload accepts only one string parameter named “message”.

When a client calls the DisplayMessage method, the compiler examines the parameters passed to the method and determines which overloaded method should be called. For example, the following code instantiates the OverloadedMethodsDemo class. The second line of code calls the DisplayMessage method with a single string parameter, and the third line of code calls the method with two string parameters.

In C#:

OverloadedMethodsDemo OverloadDemo = new OverloadedMethodsDemo();

OverloadDemo.DisplayMessage("Overloaded methods are great!");

OverloadDemo.DisplayMessage("Overloaded methods are great!", "Overload demo");

In Visual Basic .NET:

Dim OverloadDemo As New OverloadedMethodsDemo()

OverloadDemo.DisplayMessage("Overloaded methods are great!")

OverloadDemo.DisplayMessage("Overloaded methods are great!", "Overload demo")

The compiler is satisfied with these two calls because there are overloaded methods matching each set of parameters. However, if you try to call the DisplayMessage method with an incorrect number of parameters (for example, no parameters, more than two parameters, or parameters that are not string types), the compiler displays an error message.

Visual Studio .NET’s IntelliSense lets you know if a method you are calling is overloaded. For example, Figure 3 shows the popup displayed by VS .NET when entering code that calls the DisplayMessage overloaded method.

Figure 3. When you enter code that calls an overloaded method in Visual Studio .NET’s code editor, a popup displays showing details of the overloaded methods.

So, where would you use overloaded methods? When you have a method with optional parameters, you should create overloaded methods representing the different variations of parameters that can be passed to the method. This is much cleaner than having a single method checking which parameters have been passed.

Constructor methods

All Visual FoxPro classes possess an Init method that automatically executes when a class is instantiated. C# and VB .NET also have constructor methods that perform a similar function.

In C#, you declare a constructor method by adding a method with the same name as the containing class:

public class ConstructorDemo

{

  public ConstructorDemo()

  {

  }

}

In Visual Basic .NET, you declare a constructor by adding a New method to the class definition:

Public Class ConstructorDemo

    Public Sub New()

 

    End Sub

End Class

I actually prefer the VB .NET convention, because it’s easier to quickly identify a constructor that’s consistently named the same.

Notice in both code samples that neither constructor specifies a return value. This is because .NET constructors are not allowed to return values unlike Visual FoxPro where you can return a boolean False to prevent a class from instantiating.

Constructors with parameters

As in Visual FoxPro, you can specify parameters for constructor methods in .NET. This allows you to pass values to a class when it is first instantiated.

Here’s an example in C#:

public class ConstructorDemo

{

  private string connectString;

 

  public ConstructorDemo(string connect)

  {

       this.connectString = connect;

  }

}

And in Visual Basic .NET:

Public Class ConstructorDemo

    Private connectString As String

 

    Public Sub New(ByVal connect As String)

        Me.connectString = connect

    End Sub

 

End Class

In this code, the value passed in the constructor is used to initialize the value of a private field. If you don’t explicitly declare a constructor, a default constructor is automatically provided.

Here is an example of passing a value to the constructor of a class when it is instantiated.

In C#:

ConstructorDemo ConstructDemo = new

  ConstructorDemo("server=(local);uid=sa;pwd=;database=Northwind;");

And in Visual Basic .NET

Dim ConstDemo As _

    New ConstructorDemo("server=(local);uid=;pwd=;database=NorthWind;")

        As with other methods, you can also create overloaded constructor methods. Based on the parameters you pass when instantiating a class, the appropriate constructor is called.

Destructor methods

Visual FoxPro classes have a Destroy method that executes when an object is released. Typically you place code in this method to perform cleanup for the object. This works well because you have complete control over when an object is destroyed in Visual FoxPro.

In contrast, .NET has something called non-deterministic finalization. This means you don’t have explicit control over when an object is destroyed. When the last reference to a .NET object is released, the object itself is not released from memory. The object is not released until the next time the common language runtime’s garbage collector runs (see the “Garbage collection” section later in this chapter for details).

In both C# and Visual Basic .NET classes, you can add a Finalize method that executes when the object is destroyed. Just remember you can’t determine when this method is executed.

Class inheritance

One key feature of object-orientation is class inheritance, also known as implementation inheritance. C# and Visual Basic .NET both have single inheritance, meaning a class can only have one parent class. In .NET, the term base class is used in place of Visual FoxPro’s “parent class”. Personally, I prefer the term “parent class” because it’s more descriptive and more readily understood.

Specifying a base class

When you define a class in C# or VB .NET, if you don’t specify otherwise, its default base class is the .NET Framework’s System.Object class. Here is an example showing how to specify a base class.

In C#:

public class BaseClassDemo : Component

{

}

In Visual Basic .NET:

Public Class BaseClassDemo

    Inherits Component

End Class

 This code defines a class named BaseClassDemo derived from the .NET Framework’s Component class (System.ComponentModel.Component). In C#, you declare a base class by placing a colon followed by the base class name (: Component) at the end of the first line of the class declaration. In Visual Basic .NET, you place the keyword Inherits followed by the base class name on the second line of the class declaration.

Inheritance works the same way in .NET as it does in Visual FoxPro. A subclass inherits all members (properties, events, methods, and fields) from its base class, including implementation code.

Overriding inherited methods

At times, you may want a class to override an inherited method. In Visual FoxPro, the simple act of placing code in a method causes the method to be overridden. Unfortunately, in VFP all it takes is a single space character to unintentionally override a parent method.

You can “accidentally” override a method in C# and Visual Basic .NET by creating a method in a class with the same name and signature as an inherited method. For example, the following code declares a class named MyBaseClass with a single method named DisplayMessage. It also declares a subclass of MyBaseClass named “OverrideMethodDemo” that contains a duplicate DisplayMessage method.

In C#:

public class MyBaseClass

{

  public void DisplayMessage()

  {

       MessageBox.Show("Base class method!", "Override demo");

  }

}

 

public class OverrideMethodDemo : MyBaseClass

{

  public void DisplayMessage()

  {

       MessageBox.Show("Subclass method!", "Override demo");

  }

}


In Visual Basic .NET:

Public Class MyBaseClass

    Public Sub DisplayMessage()

        MessageBox.Show("Base class method!", "Override Demo")

    End Sub

End Class

 

Public Class OverrideMethodDemo

    Public Sub DisplayMessage()

        MessageBox.Show("Subclass method!", "Override Demo")

    End Sub

End Class

When you run this code, the OverrideMethodDemo.DisplayMessage method is executed, but the base class method is not. In reality, this is not a legal way to override a method in either C# or Visual Basic .NET. In both languages, the compiler catches this error and displays it as a warning (Figure 4).

Figure 4. The C# and VB .NET compilers display a warning if you create a method in a class with the same name and signature as an inherited method.

The following code demonstrates the proper syntax for overriding methods by using the override keyword (C#) or the Overrides keyword (VB .NET) in the method declaration.

In C#:

  public class MyBaseClass

  {

       public virtual void DisplayMessage()

       {

          MessageBox.Show("Base class method!", "Override demo");

       }

  }

 

  public class OverrideMethodDemo : MyBaseClass

Text Box: 		public override void DisplayMessage()

  {

       {

          MessageBox.Show("Subclass method!", "Override demo");

       }

  }

And in Visual Basic .NET:

Public Class MyBaseClass

    Public Overridable Sub DisplayMessage()

        MessageBox.Show("Base class method!", "Override Demo")

    End Sub

End Class

 

Public Class OverrideMethodDemo

Text Box:     Public Overrides Sub DisplayMessage()

    Inherits MyBaseClass

        MessageBox.Show("Subclass method!", "Override Demo")

    End Sub

End Class

When you instantiate the OverrideMethodDemo class and run its DisplayMessage method, the code in the OverrideMethodDemo subclass is executed, but the DisplayMessage method in the parent is not executed.

Virtual (Overridable) methods

Virtual methods can be overridden by a subclass. In Visual FoxPro, all methods are virtual because you can override any inherited public or protected method simply by placing code in the method of a subclass. There is no such thing as a “non-virtual” method in Visual FoxPro.

In contrast, methods are non-virtual by default in C# and VB .NET and cannot be overridden. In order to override a method, it must be specifically marked as virtual (C#) or Overridable (VB .NET) in the base class. If you look closely at the code in the previous section, you will see the DisplayMessage method in MyBaseClass was marked virtual (Overridable for VB .NET).

Text Box: ¥

If you override a virtual method, the method in the subclass marked “override” is automatically virtual too.

Extending inherited methods

More often than not, you extend rather than completely override an inherited method. In Visual FoxPro you accomplish this by placing code in a method, then issuing a DODEFAULT command. You can run DODEFAULT first, before executing your subclass code, or you can run your code first, and then issue a DODEFAULT.

To call a base class method in C#, you use the base keyword:

public class CallBaseMethodDemo : MyBaseClass

{

  public override void DisplayMessage()

  {

       MessageBox.Show("Subclass method!", "Call base method demo");

       base.DisplayMessage();

  }

}

To call a base class method in VB .NET, you use the MyBase keyword:

Public Class CallBaseMethodDemo

    Inherits MyBaseClass

    Public Overrides Sub DisplayMessage()

        MessageBox.Show("Subclass method!", "Call base method demo")

        MyBase.DisplayMessage()

    End Sub

End Class

In this example, code first executes in the subclass method and afterwards calls the base class method. You can easily reverse this order by placing the call to the base class first in the subclass method.

Polymorphism and virtual methods

Visual FoxPro is a weakly typed language, so you don’t specify the types of variables. You simply declare a variable and instantiate an object. For example:

x = CREATEOBJECT("MyClass")

As you’ve already seen, when instantiating an object in C# and in Visual Basic .NET,
you always declare the type of the variable that holds a reference to the object (assuming
VB .NET’s Option Strict is “On”). For example, the following code declares a variable
named “ClientObj” of the type Client, and then stores a new instance of the Client class into the variable.

In C#:

Client ClientObj;

ClientObj = new Client();

And in Visual Basic .NET:

Dim Client As ClientObj

ClientObj = New Client()

In this example, the code declares a variable of a specific type, and then instantiates an object from that type—no surprises here.

However, in both C# and VB .NET, when you declare a variable of a particular type it can also hold a reference to any subclass of that type. Take for example the class hierarchy shown in Figure 5, which shows Client and Invoice classes derived from the ABusinessObject class.

Figure 5. When you declare a variable of a particular type it can also hold a reference to any subclass of that type.

Given this hierarchy, you can declare a variable of type ABusinessObject and then store a reference to either the Client or Invoice object in this variable.

In C#:

ABusinessObject BizObj;

BizObj = new Client();

BizObj = new Invoice();

And in Visual Basic .NET:

Dim BizObj As ABusinessObject

BizObj = New Client()

BizObj = New Invoice()

This technique allows you to write more generic code that works with families of objects, making use of object-oriented polymorphism rather than coding to a specific class.

Hiding inherited methods

So far, you’ve learned about overriding and extending inherited methods. However, there are other situations where you may want to completely hide an inherited method and redeclare it.

To hide an inherited method in C#, use the new keyword in the method declaration:

public class HideMethodDemo : MyBaseClass

{

  public new void DisplayMessage()

  {

       MessageBox.Show("Subclass method!", "Hide method demo");

  }

}

To hide an inherited member in Visual Basic .NET, use the shadows keyword in the method declaration:

Public Class HideMethodDemo

    Inherits MyBaseClass

    Public Shadows Sub DisplayMessage()

        MessageBox.Show("Subclass method!", "Hide method demo")

        MyBase.DisplayMessage()

    End Sub

End Class

In what situations might you choose to completely hide an inherited method? First of all, you can use it to override a method not marked as virtual (or Overridable). Although I said earlier only virtual methods can be overridden, you can get around this rule by redeclaring a method with the new or shadows keyword.

 


Text Box: ¥Be judicious when deciding to hide an inherited method. If a base class method has not been marked as “virtual”, the developer may have a good reason for not allowing you to override the method. Test your code well!

For example, the following code declares a class named BaseClass with a single non-virtual method named “DisplayMessage”. It then declares a subclass of HideMethodBase named “HideMethodDemo” that redeclares the DisplayMessage method. This method even contains a call to the base class DisplayMessage method!

In C#:

public class HideMethodBase

{

  public void DisplayMessage()

  {

       MessageBox.Show("Base class method!", "Override demo");

  }

}

 

public class HideMethodDemo : HideMethodBase

Text Box: 	public new void DisplayMessage()

{

  {

       MessageBox.Show("My new method", "Hide method demo");

       base.DisplayMessage();

  }

}

In Visual Basic .NET:

Public Class HideMethodBase

    Public Sub DisplayMessage()

        MessageBox.Show("Base class method!", "Override demo")

    End Sub

End Class

 

Public Class HideMethodDemo

    Inherits HideMethodBase

Text Box:     Public Shadows Sub DisplayMessage()

    ' Hide the DisplayMessage method in the base class

        MessageBox.Show("My new method", "Hide method demo")

        MyBase.DisplayMessage()

    End Sub

End Class

There’s one “gotcha” when hiding an inherited method in this way. If you use the polymorphic trick of declaring a variable of the type HideMethodBase, but you actually instantiate an instance of the HideMethodDemo subclass instead, you get unexpected behavior when calling the DisplayMessage method.


Here’s this scenario in C#:

HideMethodBase HideBase = new HideMethodDemo();

HideBase.DisplayMessage();

And in Visual Basic .NET:

Dim HideBase As HideMethodBase = New HideMethodDemo()

HideBase.DisplayMessage()

When you run this code, rather than calling the DisplayMessage method belonging to the HideMethodDemo class, it calls the DisplayMessage method belonging to the HideBase base class instead! This is opposite of the behavior you might expect, so you need to write code with this in mind.

Another good example of a scenario where you can hide an inherited method involves third-party .NET components. Say you purchase a third-party component, subclass it, and add a custom method called PrintMessage. What happens if the company who created the component releases a new version and adds their own PrintMessage method? This leaves you with two choices. You can rename your custom method, but you may have countless lines of code in your applications calling the PrintMessage method and they all need to change.

Another option is to hide the newly inherited method causing the problem. You can then add a custom method to your subclass that calls it in the base class.

Here’s the solution shown in C#:

public class MyBaseClass

{

  public virtual void PrintMessage()

  {

       MessageBox.Show("Printing message!", "Hide method demo");

  }

}

 

public class HideMethodDemo : MyBaseClass

{

  // Hide the PrintMessage method in the base class

Text Box: 	public new void PrintMessage()

  {

       MessageBox.Show("Hiding the inherited method!", "Hide method demo");

  }

 

  // Create a custom method that calls the base class method

  public void PrintMsg()

Text Box: 		base.PrintMessage();

  {

  }

}


And in Visual Basic .NET:

Public Class MyBaseClass

    Public Overridable Sub PrintMessage()

        MessageBox.Show("Printing message!", "Hide method demo")

    End Sub

End Class

 

Public Class HideMethodDemo

    Inherits MyBaseClass

Text Box:     Public Shadows Sub PrintMessage()

    ' Hide the PrintMessage method in the base class

        MessageBox.Show("Hiding the inherited method!", "Hide method demo")

    End Sub

    ' Create a custom method that calls the base class method

Text Box:         MyBase.PrintMessage()

    Public Sub PrintMsg()

    End Sub

End Class

In this code, the HideMethodDemo class hides the PrintMessage method in the base class. It then declares a method named PrintMsg that calls PrintMessage method in the base class.

Preventing inheritance

As mentioned in the section “Virtual (Overridable) Methods”, C# and VB .NET methods are non-virtual by default, meaning they cannot be overridden in subclasses. In contrast, methods marked as “virtual” can be overridden.

There may be cases where you override a virtual method in a base class, but you don’t want other subclasses to override the method in your class. You can prevent someone from overriding your method by marking it as sealed (C#) or NotOverridable (VB .NET).

 For example, the following code declares a base class named “PreventInheritanceBase” containing a single virtual method named “DisplayMessage”. It also declares a subclass of PreventInheritanceBase named “PreventInheritanceSubclass” that marks the DisplayMessage method as sealed. This prevents subclasses of PreventInheritanceSubclass from further overriding this method.

In C#:

public class PreventInheritanceBase

{

  public virtual void DisplayMessage()

  {

       MessageBox.Show("This is a virtual method!", "Prevent inheritance demo");

  }

}

 


public class PreventInheritanceSubclass : PreventInheritanceBase