My.Internals: Examining the Visual Basic My Feature
Visual Basic Team
Updated November 2005
Summary: See the technical details on how the My feature accesses the .NET Framework functionality and items within a project. This article is not a primer on how to use the My feature, but shows how it works. (8 printed pages)
Download the MyInternals.msi sample file.
My is a new feature in Visual Basic 2005 that puts commonly used functionality at your fingertips and reduces the number of lines of code that you have to write. It does this in a way that is efficient, robust, and thread-safe. In an environment where programmer productivity matters more than ever, My can help you get things done faster, which is what Visual Basic is all about.
The purpose of this article is not to introduce the My feature or demonstrate how to use it in your applications. Rather, this article is for developers who already know what My is about and want behind-the-scenes insight into how My exposes .NET Framework functionality and items in a project.
Note This article provides detailed coverage of the workings of the My feature in Visual Basic 2005. If you are interested in an overview of this feature, please read Navigate the .NET Framework and Your Projects with "My" first.
Due to the breadth and depth of the .NET Framework, it can be daunting to find the functionality you need. To address this problem, My provides entry points to frequently used .NET Framework classes and functions. My also exposes new high-level .NET Framework classes that pull together related functionality into task-based APIs.
My exposes functionality either by returning a .NET Framework class that is instantiated and ready to go, by deferring a call to a .NET Framework method, by returning a class that aggregates functionality found in the .NET Framework common to a particular task, or by returning a dynamically generated class that provides access to items in your project.
Whenever possible, My serves as a discovery mechanism for existing classes in the .NET Framework, and exposes those types directly. As an example, consider
Public ReadOnly Property Deployment() As _ System.Deployment.ApplicationDeployment Get Return _ System.Deployment.ApplicationDeployment.CurrentDeployment End Get End Property
Other examples of direct exposure include:
My.Computer.FileSystem.OpenTextFileReader(), which returns a
My.Application.OpenForms(), which returns a
My.User, which returns
System.Security.Principal.IPrincipal and others.
My also returns new classes that provide task-based APIs for operations that were previously hard to accomplish because it was difficult to find the functionality and/or it required the orchestration of multiple objects.
Common tasks that would require the use of low-level .NET Framework APIs, or that would require multiple lines of code, are greatly simplified. As an example, consider the task of determining if a network connection is available:
Imports System.Net.NetworkInformation Public ReadOnly Property IsAvailable() As Boolean Get For Each NetInterface As NetworkInterface In _ NetworkInterface.GetAllNetworkInterfaces() If NetInterface.Type <> InterfaceType.Loopback _ AndAlso NetInterface.Type <> InterfaceType.Tunnel _ AndAlso NetInterface.OperationalStatus = _ OperationalStatus.Up Then Return True End If Next Return False End Get End Property
The code above entails detailed knowledge of several types in the
System.Net.NetworkInformation namespace. Using the facade pattern,
My.Computer.Network distills these types and their relationships into a single line of code:
A facade may also simply pull together related functionality that is otherwise difficult to find because it is defined across various classes within the frameworks. For instance, My
.Computer aggregates common functionality related to the computer. It does so by providing a single API that pulls together the functionality of several classes in the framework. As an example,
My.Computer.Screen() expose functionality defined in
Public ReadOnly Property Name() As String Get Return System.Environment.MachineName End Get End Property Public ReadOnly Property Screen() As System.Windows.Forms.Screen Get Return System.Windows.Forms.Screen.PrimaryScreen End Get End Property
Other examples of classes in My that aggregate related functionality from multiple .NET Framework types include
My.Application.Info and others.
A proxy class is an extremely thin class that forwards all calls it receives to an underlying object. For instance, if you call
My.Computer.Clipboard.GetText(), you are making a call to the proxy class method
ClipboardProxy.GetText(), which is defined as:
Public Function GetText() As String Return Clipboard.GetText() End Function
By convention, proxy classes are always suffixed with
Proxy. My utilizes proxies when accessing the clipboard, file system, and registry because the underlying classes being exposed by the proxies are made up of shared methods that otherwise wouldn't be visible in IntelliSense. Proxy classes cannot be instantiated by the user. Performance testing has shown that forwarding calls through proxies is insignificant.
In the spirit of 'functionality at your fingertips,' My provides access to the forms, Web services, resources, and settings defined in your project. If your project contains a reference to the Web service
MapDirections, for instance, you can immediately use that Web service without having to know how to spin up an instance of the Web service proxy. You can simply type:
How does that work? For the forms, Web services, settings, and resources in your project, a factory class is generated by the compiler that returns lazily created instances on demand. The factory classes are tuned to return instances in a way that is appropriate for the type of project (exe/dll/web) in which your code runs. See the section on Threading for more details.
As an example of a dynamically generated class, consider
My.Forms. This class is provided for you and defines a factory method for each Form in your project. When you access
My.Forms.Form1, the factory method checks to see if an instance of
Form1 is already open. If it is, that instance is returned. Otherwise, an instance of
Form1 is created and returned. The generated code for a project containing
Form1 would look like this:
Class MyForms 'Code in bold is generated by the compiler Public m_Form1 As Form1 Public Property Form1() As Form1 Get m_Form1 = Create__Instance__ (Of Form1)(m_Form1) Return m_Form1 End Get Set(ByVal Value As Form1) If Value Is m_Form1 Return End If If Not Value Is Nothing Then Throw New ArgumentException( _ "Property can only be set to Nothing.") End If Dispose__Instance__ (Of Form1)(m_Form1) End Set End Property End Class
Create__Instance__() function is responsible for creating an instance of the form on demand. It checks to see if the form (stored in
m_Form1) has been instantiated or not. If it has been, it is returned. Otherwise an instance is created and returned.
Create__Instance__() also catches recursive Form creation attempts.
Dispose__Instance__() is responsible for closing the Form.
My.Forms also provides the means to reintroduce default instances for forms that you may be familiar with in earlier versions of Visual Basic. Default instances make it possible to refer to an instance of a form without having to explicitly create it first.
For instance, in Visual Basic 6.0 you might have written Form1.Show() instead of:
Dim Form1Instance as Form1 Form1Instance = new Form1 Form1Instance.Show()
Because the compiler in Visual Basic 2005 utilizes
My.Forms to create default instances, you can simply write
One of the difficulties people encounter coding against a Web service is figuring out which class to code against. My.WebServices takes the guesswork out and provides an instance of the Web service proxy on demand.
My.WebServices is most appropriate for synchronous calls to a Web service. The code generated to provide instances of Web service proxies follows the same pattern as that shown for returning instances of forms.
New in Visual Basic 2005 is the Settings designer that allows you to specify application settings on an application-wide basis or per-user basis. The designer creates a class that provides strongly typed access to your settings. You can see an example of the
MySettings class in the sample project by showing all files in the Solution Explorer and looking for the
MySettings.vb file under the
Here is an example of a property generated to manage an application setting named
Partial NotInheritable Class MySettings Inherits System.Configuration.ApplicationSettingsBase <System.Diagnostics.DebuggerNonUserCode(), _ System.Configuration.UserScopedSettingAttribute(), _ System.Configuration.DefaultSettingValueAttribute("Try Me")> _ Public Property SampleUserSetting() As String Get Return CType(Me("SampleUserSetting"),String) End Get Set Me("SampleUserSetting") = value End Set End Property End Class
The generated class does all the heavy lifting for you. All you have to do to access the setting is type:
Also new in Visual Basic 2005 is the Resource designer, which allows you to add resources to your application. The Resource designer also creates a module that provides strongly typed access to the resources in your application. For instance, if you add a bitmap named
Smiley to your project, you can access it with
My.Resources.Smiley. You can see an example of the generated resource module by showing all files in the Solution Explorer for the sample project and looking for the
MyResources.vb file under the
Here is an example from the sample project of a factory property generated to return the
Public ReadOnly Property Smiley() As System.Drawing.Bitmap Get Return CType(ResourceManager.GetObject("Smiley", _resCulture),_ System.Drawing.Bitmap) End Get End Property
The strongly typed resources module that is generated for you deals with case-sensitive resource IDs, uses the
System.Resources.ResourceManager class to retrieve your resources, and manages the details associated with getting the ResourceManager created correctly for your application.
To access the same
Smiley bitmap in Visual Basic 2002 or Visual Basic 2003, you first would have had a difficult time putting the bitmap in a .resx file. Instead, you may have put it in the project as an embedded resource and had to remember to change the build action in the property grid for the resource to be Embedded Resource. Then, you would have written something like:
Dim CurrentAssembly As Reflection.Assembly = _ Reflection.Assembly.GetExecutingAssembly Dim BitMapStream As IO.Stream = _ CurrentAssembly.GetManifestResourceStream( _ "WindowsApplication2.Smiley.bmp") Dim SmileyBitmap as Drawing.Bitmap = New Bitmap(BitMapStream)
There are some important details you would have to get right in this code. You would have to know to get the currently executing assembly and call
GetManifestResourceStream()on it. You would have to remember to qualify the resource name with the root namespace name. You would have to get the casing right because the name passed to
GetManifestResourceStream()is case-sensitive. You would have to know where the stream class is defined so you could capture the return value of
GetManifestResource in a stream object. You would have to know how to create a bitmap from a stream. You likely would have encountered frustration trying to figure out why
BitMapStream kept coming back
Nothing, due to one of the aforementioned issues.
Visual Basic 2005 solves the first problem by providing a Resource Editor that makes it easy to put new or existing resources into a .resx file. My then makes it easy to access those resources. All you have to do is write:
Dim SmileyBitmap as Drawing.Bitmap = My.Resources.Smiley
Instances of classes available from My are exposed in a way that alleviates threading concerns because instances of My objects are provided per-thread. That is, the instance of
My.Computer returned on thread 1 will be different than an instance of
My.Computer returned on thread 2. This means that you don't have to write synchronization code when using My objects.
In a Web application, the instances returned from My are stored per-request.
We've examined how My exposes .NET Framework classes and how dynamically generated classes are exposed by My to give you access to items in your project, such as resources, settings, Web services, and your forms.
In the end, My is about reducing the number of lines of code you have to write and about providing ready access to the functionality you need most often. It does this in a way that is efficient, robust, and thread-safe.
In an environment where programmer productivity matters more than ever, My can help you get things done faster and more efficiently.