Discover the differences and similarities between Visual Studio .NET and Visual FoxPro.

Objects aren't useful if they don't provide specific behaviors and appearances. The behavior is provided by methods that define actions the object can perform, and the appearance comes from the data the object holds or acquires. After having provided an overview of the differences between VFP's and .NET's object model in our article in the November 2003 issue, we'll take a close look at making objects behave and appear appropriately, using methods, properties, and fields. (Fields?!? Yes, by the end of this article, you won't find those strange anymore.)

When you create classes in VFP, you spend most of your time defining methods and properties. It isn't much different in .NET. Besides the obvious differences in syntax between VFP and VB.NET or C#, there are a few differences in concepts and the way you work with methods and properties that can be confusing at first.

Methods

Methods are actions an object is able to perform. This is one way to interact with objects, no matter which language you're using. If you compare a method definition in VFP, VB.NET, and C#, you discover they aren't much different. Consider this simple example (we'll focus on the method definition because we already discussed class definitions in our last article). First, here's the VFP code:

Define Class Customer As Custom
   Function VerifyData(MyData)
      If MyData = "Howdy!"
         Return .T.
      Else
         Return .F.
      EndIf
   Endproc
Enddefine

In this example, the Customer class has a VerifyData method. If you're familiar with VFP syntax, this code snippet should be clear. The main point is that the method in the class is defined with either a PROCEDURE or FUNCTION keyword, followed by the method name and potentially some parameters and a return type.

In this example, you make use of VFP's weakly typed nature. You aren't defining what kind of return value you expect from the method, or what data type you expect the parameter to be. This is implied by the code you put into the method. Visual FoxPro 7, however, introduced the "as" keyword, which lets you provide limited type information. Using this keyword, you can re-write the example like this:

Define Class Customer As Custom
   Function VerifyData(MyData as String) as Boolean
      If MyData = "Howdy!"
         Return .T.
      Else
         Return .F.
      EndIf
   Endproc
Enddefine

You've now "typed" the method to have a Boolean return value using the "as Boolean" keywords. Of course, VFP lets you get away with defining a method that doesn't have a return type specified (or parameter types, for that matter), but it's better style to provide this type of information.

This "semi-strong typing" was introduced in VFP 7 to support IntelliSense features, as well as for the creation of COM type libraries (this is important in cases where you're going to consume a VFP COM component in a strongly typed environment such as .NET). The important thing to remember is that neither the compiler nor the runtime would complain about other parameter types being passed, despite the fact that other types may be defined. You could return a string out of this method, and the compiler would consider that OK. So, you wouldn't truly consider this to be a strongly typed class. But it's better than not providing any type information at all.

In the .NET world, things are a bit different: You have to define types of parameters and the type returned by a method, and you can't bend the rules. So, when making the leap from VFP to .NET, always keep the typed version in mind. This makes it easier to compare things. When you take type information into account, a function/method definition in VB.NET is similar to a function/method definition in VFP. Here it is:

Class Customer
    Function VerifyData(ByVal MyData As String) as Boolean
        If MyData = "Howdy!" Then
            Return True
        Else
            Return False
        End If
    End Function
End Class

As you can see, the code is similar to the VFP version, but there's one important difference: You have to explicitly specify whether the parameters are passed by-value or by-reference, otherwise, you'll get a compiler error. (However, the VS IDE helps you by automatically adding the ByVal keyword when you key in the parameter definition.) Note: Parameters are passed by-value in both VFP and C# unless defined otherwise, so you don't have to add any keywords. As you can see, the move to the VB.NET version is straightforward for VFP developers.

In the C# world, things are a bit different. Here's the same method written in C#:

class Customer
{
   bool VerifyData(string MyData)
   {
      if (MyData == "Howdy!")
      {
         return true;
      }
      else
      {
         return false;
      }
   }
}

Yes, I know, it's a bit weird. But, in a sense, it's even simpler than it is in VFP and VB.NET. You don't have to use a PROCEDURE or FUNCTION keyword. Instead, in C#, you simply define there's this "thing" that belongs to the class, and whenever you interact with it, it evaluates to a Boolean (logical) type. Then, the name of the "thing" is defined, as well as the list of parameters (the type of the parameter first, then its name). So, how does the compiler know this "thing" is a method? Well, according to the C# approach, the compiler simply says "what else would it be?", and makes all such "things" methods. This may seem strange to you, but don't worry, we'll discuss this in more detail later.

Something else to keep in mind is that in VFP, all methods always return a value (even if you type the return value as VOID). At the very least, the return value is .T., even if you never issue a RETURN command. In .NET, you have finer control over that. In C#, all you have to do is declare the return type of the method as void, then never use a return command with a value, and you have a method that doesn't return anything at all. In VB.NET, instead of defining a method with the FUNCTION keyword, you can define it with the SUB keyword to get the same behavior. Subs (sub-routines) don't return any value:

Sub DoSomething()
     'Run any code...
End Sub

The code for calling an object's methods is similar in VFP, VB.NET, and C# (except in C# there's a semi-colon at the end of the line):

oObject.VerifyData(Paremeters)

Method visibility

At this point, you may have asked yourself: "What about the scope of the method?" Well, we're glad you asked, because this is an important subject, which we've omitted in the previous samples. When you define a method in VFP without using a modifier (such as PROTECTED or HIDDEN), the method is considered Public (visible to the class itself, to its subclasses, and just about anywhere and to anyone else). This is also true in VB.NET. C#, on the other hand, considers the method "Private." This means it's visible only to the class itself, but invisible anywhere else (including classes that inherit from it). Keep that in mind when you write methods in C# and don't explicitly define the method's visibility.

Table 1: Visibility options -- Comparison of VFP, C#, and VB.VFP ModifierC# ModiferVB ModifierVisibilityPublicPublicPublicFully accessible outside the class.ProtectedProtectedProtectedAccessible only to the class itself and its derived classes.N/AInternalFriendAccess is limited to other classes in the current assembly.N/AProtected InternalProtected FriendAccess is limited to the current assembly or types derived from the containing class.HiddenPrivatePrivateAccessible only to the class itself, but not from its derived classes.

Table 1 shows what options for visibility are available in .NET and how they compare with VFP. In .NET, it's common practice to identify the visibility of all methods, even if they adhere to the language's defaults. We recommend this technique as well, because the default is different in different languages, which can make things a bit confusing at times. Here's the VB.NET version with explicitly declared visibility of the method (and, for completeness, the class as well):

Public Class Customer
    Public Function VerifyData(ByVal MyData As String)_
     as Boolean
        If MyData = "Howdy!" Then
            Return True
        Else
            Return False
        End If
    End Function
End Class

And the C# version as well:

public class Customer
{
   public bool VerifyData(string MyData)
   {
      if (MyData == "Howdy!")
      {
         return true;
      }
      else
      {
         return false;
      }
   }
}

Note that the VB.NET class is functionally identical to the previous example. However, the C# version changed significantly because the method is now public.

Method overloading

In VFP, methods must have unique names, which means one class can't have more than one method with the same name. This isn't true in .NET, where a class can have multiple methods with the same name as long as their parameters differ in number and/or type. (This is known as the method's "signature.") This feature is known as method overloading.

As we've already mentioned, given VFP's weakly typed nature, you can pass any type of parameter to a method. As a result, you frequently end up testing the type of the parameter passed to determine whether you can use the parameter safely, or even decide which kind of code to execute depending on the type and number of parameters passed. That means a lot of coding if you want to write less error-prone code. In addition, all the code that handles different functionality depending on the parameters gets mixed up in the same place. Also note that methods defined with multiple parameters assume a default value of a logical .F. for all omitted parameters. Therefore, it's perfectly acceptable in VFP to call a method and pass fewer parameters than the definition of the method requires.

Consider the following scenario: You have a Customer object that has a SendPassword public method. This method is called every time you send a password for a given customer. It expects to receive an Integer parameter that should be the customer's PK or a string that should be the customer's e-mail address, and the optional second parameter should be a Boolean indicating whether the message should be sent right away or queued in a message queue. You'd call this method like this (in VFP):

oCustomer = CreateObject("Customer")

*-- Send an e-mail right away for Customer PK 35
? oCustomer.SendPassword(35)

*-- Queue an e-mail for Customer PK 35
? oCustomer.SendPassword(35, .T.)

*-- Send an e-mail right away for Customer e-mail
*-- "classala@eps-software.com"
? oCustomer.SendPassword("classala@eps-software.com")

*-- Queue an e-mail for Customer e-mail
*-- "classala@eps-software.com"
? oCustomer.SendPassword("classala@eps-software.com", .T.)

In VFP, you must write defensive code to make sure users of this class invoke the method properly. You can't let them use the class like this, for example:

*-- No parameter is passed.
? oCustomer.SendPassword()

*-- The first parameter is not the expected type.
? oCustomer.SendPassword(Date())

*-- The first parameter is OK, but the second one is not.
? oCustomer.SendPassword("classala@eps-software.com", Date())

With that in mind, this is probably the code you'd end up writing:

Define Class Customer As Session
Procedure SendPassword(lxParameter as Variant, llQueueMessage as Boolean) As Boolean
   Local lnPCount
   lnPCount = Pcount()
   If lnPCount = 0
         Assert .F. Message "No parameters were specified."
        Return .F.
   Endif

   Local lcVarType
   lcVarType = Vartype(lxParameter)

   Do Case
   Case lcVarType = "N"
         *-- Search Customer by its PK.
   Case lcVarType = "C"
         *-- Search Customer by its e-mail address.
   Otherwise
         Assert .F. message ;
          "Parameter of the wrong type: lxParameter"
         Return .F.
   EndCase
 If lnPCount = 2
         If Vartype(llQueueMessage) = "L"
                  If llQueueMessage
                      *-- Put e-mail in some message queue.
                  Else
                     *-- Send e-mail right away.
                  EndIf
         Else
                  Assert .F. message ;
                      "Parameter of the wrong type: llSendRightAway"
                  Return .F.
         EndIf
   Else
         *-- Send e-mail right away.
   EndIf
   Return .T.
Endproc
Enddefine

As you can see, there's a lot of code just to make sure the caller of the method is passing the appropriate parameters. Therefore, if you don't write code like this, the application can be broken fairly easy. Also, the code ends up cluttered with logic (parameters checking) that has nothing to do with the ultimate action you're trying to accomplish (in this case, sending an e-mail).

With .NET's overloaded methods, you have the compiler checking the parameters for you. That means, once again, if you try to call a method passing a parameter of a different type than the one expected, the compiler produces an error reporting that. Not just that, but when you call a method, .NET can decide which overload (that is, which version of the method) is the best to run. And, to make your life even easier, VS.NET's IntelliSense lists all overloads for the method, letting you know how to call the method. Here's an example (for the sake of space, let's only look at the C# version, because the concept is the same no matter what .NET language you use. The only difference between C# and VB.NET is the syntax):

public class Customer
{
   public bool SendPassword(int pkCustomer)
   {
      // Search Customer by PK.
      // Send e-mail right away.
      return true;
   }
   public bool SendPassword(int pkCustomer,
    bool llQueueMessage)
   {
      // Search Customer by PK.
      if (llQueueMessage)
      {
         // Put e-mail in some message queue.
      }
      else
      {
         // Send e-mail right away.
      }
      return true;
   }
   public bool SendPassword(string customerEmail)
   {
      // Search Customer by e-mail.
      // Send e-mail right away.
      return true;
   }
   public bool SendPassword(string customerEmail,
    bool llQueueMessage)
   {
      // Search Customer by e-mail.
      if (llQueueMessage)
      {
         // Put e-mail in some message queue.
      }
      else
      {
         // Send e-mail right away.
      }
      return true;
   }
}

Because there are three methods with the same name, this method appears to define the same method three times. In reality, however, the signature of the methods (name, parameter number and types, return type) are different, and therefore, the methods are considered to be different. You can now call each method simply by providing the right parameters:

// Customer PK only
oCustomer.SendPassword(1);

// Customer PK and queuing indicator
oCustomer.SendPassword(1,true);

// e-mail only
oCustomer.SendPassword("Claudio@eps-software.com");

// e-mail and queuing indicator
oCustomer.SendPassword(Claudio@eps-software.com,true);

Not a single line of code is required for checking the type or number of parameters passed; .NET manages to call the appropriate overload of the method, according to the number of parameters and type passed when calling the method. No further checking is required. Also, the compilation fails if the compiler encounters a call to the method that has no matching overload, like this:

// No parameter is passed.
oCustomer.SendPassword();

// A DateTime is passed.
oCustomer.SendPassword(DateTime.Now);

One way VFP developers have been approaching this kind of scenario has been by creating separate methods for each action. For example, instead of having one SendPassword method, then deciding what to do based on the type and number of parameters, we've been creating separate methods. So, to relate this to the example, you'd have one method named SendPasswordByPK and another named SendPassword-ByEmail. Then each one could have the optional parameter to indicate whether it should queue the e-mail (unless you also want to create two different methods to handle this).

Although that could be a reasonable solution for some scenarios, it wouldn't be for others. The main problem is you end up with a cluttered public interface for your object (instead of having one SendPassword that provides the functionality, you have several methods named similarly but accomplish slightly different tasks).

We'll give you a good example. The .NET Framework has a Graphics class (that's part of the GDI+ feature) that has a DrawImage method. You can call this method in several different ways to draw an image. For example, you may want to draw an image based on certain coordinates, an existent bitmap file, or an existing Image object, but respecting given coordinates, etc. Just so you get an idea of what we're talking about, the DrawImage has 30 (yes, thirty) overloads! Imagine how terrible it would be having an object with 30 methods on its public interface, with names such as DrawImageBy-Coordinate, DrawImageFromBMP, DrawImageFromImage-ControlRespectingCoordinates, etc. Another example is the Math class' Round() method. Because .NET features several different numeric data types, and you can call the Round() method with an indicator for the number of digits to which you want to round, you'd end up with methods such as Round-Decimal(), RoundDecimalToDigits(), RoundFloat(), etc. What a mess! Overloading solves this problem. You might think this is a rather strange technique at first, but it makes sense due to the strongly typed nature of the .NET environment. Things would simply get out of hand without overloading.

Optional parameters are another important aspect of method overloading. In a type-safe environment, parameters generally aren't optional. When a method is defined to accept a certain parameter, there's no choice but to pass it. A common approach to providing optional parameters is to create overloads that don't have all the parameters. For example, you could create SendPassword() methods that can accept a PK or an e-mail address, and optionally, a queuing indicator, using this approach:

public class Customer
{
   public bool SendPassword(int pkCustomer)
   {
      return this.SendPassword(pkCustomer,false);
   }
   public bool SendPassword(int pkCustomer,
    bool llQueueMessage)
   {
      // Real code goes here...
      return true;
   }
   public bool SendPassword(string customerEmail)
   {
      return this.SendPassword(customerEmail,false);
   }
   public bool SendPassword(string customerEmail,
    bool llQueueMessage)
   {
      // Real code goes here...
      return true;
   }
}

As you can see, the overloads of the method that don't receive the queuing parameter don't have any code. Instead, they simply call the more complex version of the method, and pass a default value for the second parameter.

Properties, member variables, and fields

.NET's properties and fields are the cause of much confusion for the VFP developer. The reason for this is VFP and .NET properties are drastically different in nature. In VFP, a property acts as a variable, storing instance data of an object, and it might also have accessor methods (Access and Assign methods), which control access to the property.

In C#, a field is a variable defined at the class level (in VB, it's known as a member variable). A field stores data in an object, whereas a property is a pair (usually) of accessor methods that controls access to data inside an object. To explain this concept, let's take a step back and look at what properties are and why we need them.

When OOP was first introduced, the only members objects exposed to the outside world were methods. That's also the reason why many OOP compilers assume everything that's exposed on an object is a method (as in the case of the C# compiler). However, people realized that methods weren't convenient or natural when it comes to object attributes (such as the color of a visible object), because this always required duplicate effort (one method to set the value, and another method to get the value). It's much more natural to ask "What is the color of this?" then "Give me the color value," and "What does that mean?"

To solve this dilemma, the property was introduced. It simply lets you query and set a property such as "color." Under the hood, of course, things are still similar to the get/set days. But it's a convenient shortcut. What's important to realize, however, is that this shortcut has nothing to do with storing the value the property deals with. That value is typically stored in a "member variable." This is a construct that generally behaves much like any other variable, but it's scoped to the object (i.e., it belongs to the object).

When Visual FoxPro was introduced, all objects had methods and properties. However, Visual FoxPro properties didn't adhere to what we describe above. Instead, member variables and properties have been merged into a single entity. The VFP architects decided that in most scenarios, properties simply marshal the call to an internal value. So they decided that member variables automatically become properties. Therefore, you can design a property in Visual FoxPro like this:

Define Class Customer as Session
   CustomerPK = ""
EndDefine

There you have it: a Customer class with a CustomerPK property. Of course, properties can have visibility assignments, as in this example:

Define Class Customer as Session
   PROTECTED CustomerPK
   CustomerPK = ""
EndDefine

But the concept here is still the same: You define a variable on class level, and its value is automatically exposed as a property.

In the more recent versions of VFP, however, the language architects acknowledged that properties aren't always the equivalent of the underlying value. For this reason, Access and Assign methods were added to the language. Now, you can define a property and its associated accessor methods with code like this:

Define Class Customer as Session
   CustomerPK = ""

   Procedure CustomerPK_Access()
      Return This.CustomerPK
   EndProc

   Procedure CustomerPK_Assign(xValue)
      This.CustomerPK = xValue
   EndProc
EndDefine

Conceptually, this is almost the opposite of the Set() and Get() method approach in the pre-property days. VFP's accessor methods (when defined) intercept calls to the member variable, giving you the opportunity to add custom behavior. For example, if you wanted to make sure the alphanumeric customer PK only contains upper-case characters, you'd do this:

Procedure CustomerPK_Assign(xValue)
   This.CustomerPK = Upper(xValue)
EndProc

Or, perhaps you want to restrict access to a property to be read-only. In that case, you could simply not assign the new value to the internal variable:

Procedure CustomerPK_Assign(xValue)
   * We ignore the assignment!
EndProc

Note that although technically, access and assign methods intercept calls, rather being the means of making the call, the resulting functionality is similar to what occurs in a Get() and Set() dominated environment. To provide a bit of trivia: Take a look at how VFP properties are exposed in COM type libraries. They get turned into set and get methods! Under the hood, everything on an object is really a method.

How does this relate to .NET? Well, in .NET, you're back to the more classical approach of having properties and member variables be separate entities. Therefore, classes can define those variables (also known as "fields"), then expose them as properties. Those properties often control access to private fields in a class. For example, a "CustomerPK" property could use a DataSet object to retrieve the value from the data source. Or, perhaps a property sets the value in a node in an XML document.

You could write the same customer class shown above in VB.NET:

Public Class Customer
   Private _CustomerPK As String

   Public Property CustomerPK() As String
      Get
         Return Me._CustomerPK
      End Get

      Set(ByVal Value As String)
         Me._CustomerPK = Value
      End Set
   End Property
End Class

As you can see, the member variable (this is the term VB.NET uses) is defined as a private string variable (private is .NET's version of "hidden") called "_CustomerPK". On the other hand, the property is called "CustomerPK". It's therefore a completely different entity. The two items don't have much to do with each other. In fact, you could have named the member variable "x", or any other name, for that matter.

Note also that the property is defined similarly to how you'd define a method, except that instead of using the "Function" or "Sub" keyword, you use the "Property" keyword. This makes sense, because a true property is still a pair of methods. And, the "Property" keyword indicates to the compiler to expect exactly that: Set() and Get() sub-methods defined within the property. The code in this pair of methods is straightforward (at least in this example). All you do is access the private "_CustomerPK" member variable. (This is where you could refer to "x" if that was the name you used for the variable.)

The C# version is conceptually similar:

public class Customer
{
    private string _CustomerPK = "";

    public string CustomerPK
    {
       get
       {
          return this._CustomerPK;
       }
       set
       {
          this._CustomerPK = value;
       }
    }
}

Just like in VFP, it's possible to create read-only or write-only in .NET. For instance, in C#, if you wanted to create a read-only property, you'd implement a Get method (leaving the Set method out). If you wanted to create a write-only property, you only implement the Set method. In VB.NET, it's basically the same. The only difference is that you have to add the ReadOnly or WriteOnly modifier to the property definition, depending on what you're trying to accomplish. For example:

Public ReadOnly Property CustomerPK() As String
   Get
      Return Me._CustomerPK
   End Get
End Property

This is a safety mechanism, indicating to the compiler that you meant what you typed. Also, the VB.NET IDE automatically adds Set() and Get() methods whenever you type "Public Property...". If you add the "ReadOnly" or "WriteOnly" keywords, the IDE won't generate the unneeded methods.

What's interesting is the number of times we find ourselves writing .NET properties that don't correspond to a field or member variable, a scenario that's unusual in Visual FoxPro. In a strongly typed environment such as .NET, it makes much more sense to separate the two parts. Consider a label object with a Color property. In a .NET world, the property would probably be strongly typed as a "Color" object (based on the Color class provided by the .NET Framework). Internally, however, the storage is probably very different. In this example, we could imagine that, internally, a GDI+ Brush object would be used. The property, however, wouldn't require other developers to understand these details and expose the setting as a simple property. Another example would be any type of object that exposes data stored in a database. In that case, it's likely the properties access an underlying data-related object, such as a DataSet or a DataReader (.NET's equivalent of VFP's cursors).

Familiar cornerstones

Methods and properties are one of the cornerstones of object-oriented development. As we've demonstrated in this article, .NET properties and methods are similar in concept to properties and methods in VFP. This is especially true when it comes to calling them. The biggest surprise is probably the fact that properties and their member variables are two separate entities. If you think of these things as mandatory accessor methods, you should be fine. And after you use this technique for a while, it'll feel natural.

In the next article in this series, we'll take a closer look at .NET's great new feature: Inheritance.

By Claudio Lassala and Markus Egger