Introduction to .NET for ArcObjects developers


Summary Microsoft .NET is a technology and framework for developing applications. Although ArcObjects are built on top of a Component Object Model (COM), the ArcObjects .NET software development kit (SDK) provides COM interops and primary interop assemblies (PIAs) that allow the developer to create instances of COM types and call its methods as though they were native .NET instances.

This topic provides an introduction to .NET, focusing on details that will assist a developer with a COM, and particularly, Visual Basic for Applications (VBA) or VB6 background.

In this topic


Introduction to the .NET Framework

The Microsoft .NET Framework is a software framework supported by Microsoft Windows operating systems. It has the following two main components:
  • Base Class library
  • Common Language Runtime (CLR)
The Base Class library is a collection of managed code types including classes, interfaces, structures, enumerations, and delegates. The types provide the developer with functionality similar to that previously used through the Windows application programming interface (API). It includes definitions of types (from integers and strings to hashtables and other collections), along with handling common functionality including user interface (UI) design, file and database interaction, algorithms, exceptions, string manipulation, threading, and drawing, among others. It can be used to build a variety of applications and services.
The CLR is the .NET runtime execution engine. It loads assemblies, manages and executes .NET code and provides background services, such as security, COM interop, and garbage collection. Code that takes advantage of the CLR is called managed code, while code that runs outside the CLR is called unmanaged code.

Choosing a language (VB .NET vs. C#)

The .NET Framework supports a variety of languages. The most popular, and the languages supported for ArcObjects development, are VB .NET and C#. While both languages consume the Base Class library, there are a few differences. C# supports operator overloading and the ability to handle unmanaged code, while VB .NET does not. Keeping that in mind, the most important factor in choosing your ArcObjects development language is your prior experience and comfort with each language. Most VBA and VB6 programmers will find VB .NET more familiar, while C++ and Java developers will find more similarities with C#.

Quick guide to .NET

This section introduces some details of programming in .NET. It is not a comprehensive guide, but is focused on the VBA or VB6 developer who is moving into .NET development. For complete .NET help, see the Microsoft Developer Network (MSDN) Web site's Visual C# Developer Center or Visual Basic Developer Center.

Namespaces

Namespaces are used in .NET to organize similar objects and prevent naming conflicts. They use a dot convention to specify a hierarchy. For example, ArcObjects for ArcGIS Engine controls are located in the ESRI.ArcGIS.Controls namespace, and to access the IToolbarControl interface, use the fully qualified path ESRI.ArcGIS.Controls.IToolbarControl.
You can reference namespaces in your code using a directive (using in C# or Imports in VB .NET) as shown in the following code example. Once those statements are in place, you can reference types within the referenced namespaces without qualification. For example, if you add a using or Imports statement for ESRI.ArcGIS.Controls in your code, you will be able to access ESRI.ArcGIS.Controls.IToolbarControl as IToolbarControl, without the ESRI.ArcGIS.Controls namespace preceding it at each use.
[C#]
using ESRI.ArcGIS.Controls;
[VB.NET]
Imports ESRI.ArcGIS.Controls

Assemblies

Assemblies are binary files that contain the project and type information, and are logically groupings of functionality. To use a namespace in your code, you must include a reference to the namespace that contains it in your project. To add a reference to an assembly, right-click your project's name in the Solution Explorer in Visual Studio, and select Add Reference or Add ArcGIS Reference.

Classes

Classes are the building blocks for custom types. They group variables, properties, methods, and events, defining the attributes and behavior of the type.
All classes must have at least one constructor and to be creatable in COM, it must have a public default constructor with no parameters. If you do not define a constructor, the VB .NET and C# compilers will supply a default one with no parameters. However, if you do define a parameterized constructor, you will need to provide a constructor with no parameters as well if you want the class to be creatable in COM.  
The definition of a class starts with an access modifier. Classes can be internal (the default) or public. See the following code example:
[C#]
public class Animal
{
    int m_numerOfLegs;
    bool m_isAlive;

    public Animal()
    {
        m_isAlive = true;
        m_numberOfLegs = 4;
    }

    public Animal(int legCount, bool living)
    {
        m_isAlive = living;
        m_numberOfLegs = legCount;
    }

    public int LegCount
    {
        get
        {
            return m_numberOfLegs;
        }
        set
        {
            m_numberOfLegs = value;
        }
    }
}
[VB.NET]
Public Class Animal
    Private m_numerOfLegs As Integer
    Private m_isAlive As Boolean
    
    Public Sub New()
        m_isAlive = True
        m_numberOfLegs = 4
    End Sub
    
    Public Sub New(ByVal legCount As Integer, ByVal living As Boolean)
        m_isAlive = living;
        m_numberOfLegs = legCount
    End Sub
    
    Public Property LegCount() As Integer
        Get
        Return m_numberOfLegs
        End Get
        Set(ByVal Value As Integer)
        m_numberOfLegs = Value
        End Set
    End Property

End Class
Class fields and members are instance or static. Instance members can only be accessed through an instantiated instance of the class, and this is the default category. Static members belong to the class, not an instance of the class. They are defined by using the keyword static (C#) or Shared (VB .NET). See the following code example:
[C#]
// To define the class.
class MyMap
{
    // An instance member.
    public int mapCount;

    // A static member.
    static SaveFile(string file, string contents)
    {
        System.IO.File.WriteAllText(file, "This is file " + file + "\r\n\r\n" +
            contents);
    }
}

// To use the class's static member.
MyMap.SaveFile("myfile.txt", "here are contents");

// To use the class's instance member.
MyMap thismap = new MyMap();
thismap.mapCount = 3;
[VB.NET]
' To define the class.
Friend Class MyMap
' An instance member.
Public mapCount As Integer

' A static member.

Private Function SaveFile(ByVal File As String, ByVal contents As String) As [Shared]
    System.IO.File.WriteAllText(File, "This is file " & File & Constants.vbCrLf & Constants.vbCrLf & contents)
End Function

End Class

' To use the class's static member.
MyMap.SaveFile("myfile.txt", "here are contents")

'To use the class's instance member.
Dim thismap As New MyMap()
thismap.mapCount = 3
The static (Shared) members are not the same as the members defined using the static keyword in VB6.

Class destruction and garbage collection

All classes have a destructor. In C# it is named by the class name, preceded by a tilde (~) symbol. In VB .NET, it is a method called Finalize. They should never be called by a class, but are called automatically by the garbage collector when the instance of the class is no longer in use.
The garbage collector runs whenever the memory for a process is getting full and calls the destructor on objects that are no longer in use. As a result, you will not know exactly when a destructor is going to be called. See the following code example:
[C#]
class Animal
{
    public Animal(){}

    ~Animal(){}
}
[VB.NET]
Friend Class Animal

Public Sub New()
End Sub

Protected Overrides Sub Finalize()
End Sub

End Class
In .NET code, COM objects are released at some point after they are no longer referenced. If a COM object needs to be released at a specific point, the Marshal.ReleaseCOMObject method of the System.Runtime.InteropServices namespaces should be called. For more information, see Releasing COM references.
In VB6, Class_Terminate was called when the object was no longer referenced. In .NET, the garbage collector handles the call for you but as a result, you cannot be sure when the destructor will be called.

Inheritance

Inheritance is a key component of object-oriented programming, allowing developers to use the functionality of an existing class and expand upon it without having to rewrite the entire class. This provides support for "is-a" relationships. If you have a class, Animal, that defines some attributes about how an animal behaves, you can write a class, Dog, that inherits from the Animal class, giving it the same attributes the Animal class has, while also allowing you to overwrite those attributes, as well as adding additional ones specific to your derived class.
.NET only supports single inheritance; a class can only be derived from another single class.
In VB6, COM only supported interface inheritance. See the following code example:
[C#]
public class Dog: Animal
[VB.NET]
Public Class Dog Inherits Animal

.NET interfaces

Similar to COM interfaces, .NET interfaces contain the definitions for related methods and properties, but no implementation. See the following code example:
[C#]
public interface IBark
{
    void Bark();
}
[VB.NET]
Public Interface IBark

Sub Bark()
    End Interface
Classes can then implement multiple interfaces, which allows an object to be composed of multiple types, since as discussed previously, only single inheritance is supported in .NET. See the following code example:
[C#]
public class Dog: IBark, IRun
[VB.NET]
Public Class Dog Implements IBark, IRun

Access modifiers

Access modifiers define where a type or type member can be accessed. The following access modifiers are supported in .NET:
  • public(C#) or Public (VB .NET)—No restrictions as long as the containing assembly is referenced.
  • private (C#) or Private (VB .NET)—Only accessible by code in the same assembly.
  • protected (C#) or Protected (VB .NET)—Only accessible by code in the same class or a derived class.
  • internal (C#) or Friend (VB .NET)—Only accessible by any code in the same assembly.
  • protected internal (C#) or Protected Friend (VB .NET)—Only accessible by code in the same assembly or a derived class in another assembly.
  • Classes, structs, and interfaces can only be public or internal, with internal as the default setting.
  • Class and struct members can have any of the access types. This includes nested classes and structs.
  • Interface and enumeration members are always public.

Overloading and overriding

Overloading a method allows a class to have multiple methods of the same name, but different signatures or sets of parameters. See the following code example:
[C#]
class Map
{
    void AddData(Point p){}

    void AddData(Polygon p){}
}
[VB.NET]
Friend Class Map

Private Sub AddData(ByVal p As Point)
End Sub

Private Sub AddData(ByVal p As Polygon)
End Sub

End Class
Overriding a method allows particular functionality to be defined in a derived class, replacing that of the base class. See the following code example:
[C#]
class Animal
{
    public abstract void Speak();
}

class Dog: Animal
{
    public override void Speak()
    {
        Bark();
    }
}
[VB.NET]
Friend Class Animal
Public MustOverride Sub Speak()
End Class

Friend Class Dog
Inherits Animal
Public Overrides Sub Speak()
Bark()
End Sub

End Class

Naming conventions

Variables should be named to reflect their purpose or meaning. The following are guidelines in naming them:
  • Use Pascal casing (capitalizing the first letter in each word) for namespaces, classes, members, and constants. See the following code example:
[C#]
const string MapUnits = "meters";
[VB.NET]
Const MapUnits As String = "meters"
  • Use camel casing (first letter lowercased, following words capitalized) for variables and parameters. See the following code example:
[C#]
bool isVisible;
[VB.NET]
Dim isVisible As Boolean
In VB6, Hungarian notation was preferred. In .NET, variable names are encouraged to reflect the variable's purpose, not type.
  • Precede member variables with m_.
In VB6, it was common to name interface pointer reference variables starting with the letter "p" as in pMapControl. The p should no longer precede interface pointer references in .NET.

Data type conversions

VB .NET and C# perform some conversions automatically, such as those that will not result in a loss of data. These conversions are called widening. For example, going from an integer to a double.
To perform a narrowing conversion, where some data might be lost, requires casting. See the following code example:
[C#]
double width = 3.5;
int paddedWidth = (int)width;
[VB.NET]
Dim Width As Double = 3.5
Dim paddedWidth As Integer
paddedWidth = CType(Width, Integer)
For details on these conversions, see Casting across ArcObjects interfaces.

Changes to using variables from VB6

Between VB6 and .NET, there are changes in how variables are used:
  • VB6 used the Set keyword, while .NET does not.
  • .NET supports variables defined in blocks. The variable is visibile from its definition until the end of the block (such as an if statement) that it is defined in. If it needs to be visible outside that block, its definition should be moved outside the block.

    See the following code example:
[C#]
if (x > 5)
{
    bool overFive;
    overFive = true;
}

MessageBox.Show(overFive.ToString());
[VB.NET]
If x > 5
    Dim overFive As Boolean
    overFive = True
End If
MessageBox.Show (overFive.ToString())
  • Multiple variables can now be defined on a single line. See the following code example:
[C#]
int x, y;
[VB.NET]
Dim x, y As Integer
  • Variables in .NET can be defined and initialized on the same line. See the following code example:
[C#]
int x = 32;
[VB.NET]
Dim x As Integer = 32

Changes in arguments from VB6

There are a few differences in the default settings for variables in VB .NET and C# from the defaults in VB6:
  • When passing arguments, VB .NET and C# default to passing by value, where VB6 passed by reference.
  • VB6 supported optional parameters. They are not supported in C# and instead, overloading should be used. In VB .NET, optional parameters are allowed if default values are provided.
  • VB6 only required a parenthesis if a return value was expected. They are always required in C# and VB .NET.

Working in Visual Studio

The Visual Studio integrated development environment (IDE) provides developers with tools to help write applications. It is a an authoring, compiling, and debugging tool. For trial versions, a getting started guide, and other learning resources, see MSDN's Visual Studio Developer Center.

Introduction to the Visual Studio application files

The following files are created as part of projects in Visual Studio:
  • Solution file (.sln)—Organizes projects.
  • Project file (.vbproj or .csproj)—Stores project information and associated file lists for VB .NET and C# projects, respectively.
  • Project user options file (.vbproj.user or .csproj.user)—Stores project option settings for VB .NET and C# projects, respectively.
  • Code file (.vb or .cs)—Holds the VB .NET or C# code, respectively. Includes form definitions, control settings, and code procedures.
  • Resource file (.resx)—Defines resources used by the form, including text strings and graphics.
  • bin folder—Contains compiled code.
  • obj folder—Contains files for debugging code.

Differences from the VB6 environment

Working in Visual Studio is a different experience than using the VB6 environment. As you get started, you will notice some of them right away. When managing projects in VB6 with the Project Explorer, project groups (.vbg) were optional and named when saved. In Visual Studio, the Solution Explorer displays your projects and a solution (.sln) is created automatically.
Edits could be made during debugging in VB6. VB .NET does not support edits while in debug mode, although C# does.