Attributes in VB .NET
It's new in VB .NET!
Attribute is a word that has been overloaded. Overloading is not just an object oriented programming technique. It's also something that happens to ordinary words when you're trying to figure out how to use a sophisticated development environment like VB .NET! Depending on your previous experience, you might have run into attributes before. In VB .NET, it represents a new feature with really great potential. You'll see more and more of attributes as you learn advanced programming techniques.
Here's an introduction to how attributes are used in VB .NET.
If you have a background in XML or HTML, the word attribute is a modifier of an element. For example, in the HTML Anchor tag:
HREF is an attribute of the element A.
Visual Studio uses XML attributes 'behind the scenes' in a lot of ways and it's important for people just learning VB .NET to avoid confusing them with the 'other' attributes. We took advantage of XML attributes when we demonstrated one way to use the less expensive VB .NET Learning Edition and still be able to compile class libraries. (Learn more about that in the article, A Better Way To Inherit?.)
But (just to confuse you?), Visual Studio includes a technique borrowed from C++ that is also identified by the term attributes. If you have programmed Microsoft's MTS or COM, you might have used this type of attribute before .NET arrived. Attributes were used a great deal in COM, but they had to be programmed using a language called IDL (Interface Definition Language) and were generally considered to be a more advanced technique. VB .NET brings the same idea into the mainstream and gives it both power and makes it a lot easier to use. For example, attributes were only keywords in COM programming. But in VB .NET, they have the advantages of being objects.
Here's the 'book' description of VB .NET attributes straight from Microsoft:
Attributes are keyword-like tags in which you can specify additional information about entities defined in Visual Basic .NET applications. Attributes, which are saved with an assembly's metadata, annotate programming elements such as types, fields, methods, and properties.
Another definition ... maybe a little easier to understand ... is that an attribute is simply a class that inherits from System.Attribute.
(Trust Microsoft to make things harder than they have to be!)
This is the type of attribute that will be introduced in this article.
Attributes in VB .NET
Page 2 - The Two Types of Attributes
Any application can use the added information provided by an attribute. In general, there are two types of attributes in VB .NET: predefined and custom. A predefined attribute is used by the .NET Framework itself. You can use the same techniques in your own applications with custom attributes.
Here's just a few of the predefined attributes taken from Microsoft's documentation. Notice that a recommended coding practice is to create an attribute name by dropping the trailing string "Attribute".
Indicates to the compiler that the class should be exposed as a COM object. Specific to Visual Basic .NET.
Specifies the size of a fixed-length string in a structure for use with file input and output functions. Specific to Visual Basic .NET.
Specifies the size of a fixed array in a structure for use with file input and output functions. Specific to Visual Basic .NET.
Makes a method callable using the SOAP protocol. Used in XML Web services. SerializableAttribute Class Indicates that a class can be serialized.
Determines how a parameter should be marshaled between the managed code of Visual Basic .NET and unmanaged code such as a Windows API. Used by the common language runtime.
Specifies how an attribute can be used. DllImportAttribute Class Indicates that the attributed method is implemented as an export from an unmanaged DLL.
The three attributes that are specific to Visual Basic .NET are: COMClassAttribute, VBFixedStringAttribute, and VBFixedArrayAttribute.
Page 3 - An Example: The Predefined VBFixedString Attribute
To illustrate the general idea behind the use of attributes in VB.NET, let's look at how VBFixedString is used in a real program. The problem that this attribute solves is created by the fact that in VB.NET, a string has the characteristics of an array of Char instances. (An array of Chars, in other words.)
When you create a file using a structure containing strings and VB.NET's FilePut, you don't get what you might expect because VB.NET puts in extra information because it's an array of Chars. Consider this example program. (PrefixString and PostfixString are there just to provide a visual marker in the created file.)
Public PrefixString As String
Public myString As String
Public PostfixString As String
Private Sub Button1_Click( _
ByVal sender As System.Object, _
ByVal e As System.EventArgs) _
Dim myRecord As VariableType
FileOpen(1, "F:\TESTFILE.TXT", _
myRecord.PrefixString = "X"
myRecord.myString = "AAAAA"
myRecord.PostfixString = "X"
When the resulting program is executed, here's what the file looks like in Notepad. To solve this problem, the structure is changed by adding the VBFixedString attribute. (Dim myRecord As FixedType must also be changed.)
<VBFixedString(1)> Public PrefixString As String
<VBFixedString(5)> Public myString As String
<VBFixedString(1)> Public PostfixString As String
This results in what you need - an all-character file that you can use in other systems.
In the example above, each element - such as Public PrefixString As String - is called the target of the attribute in front of it. All .NET programming elements (assemblies, classes, interfaces, delegates, events, methods, members, enum, struct, and so forth) can be targets of attributes.
If you scan the list of attributes implemented in .NET, you will notice that one way to describe the way .NET uses attributes is to simply change the way .NET works to solve some problem that is difficult to solve with regular language elements. This makes them seem to be sort of a programming 'fudge factor' and you might wonder why Microsoft didn't just make the functions solved with .NET attributes part of the Visual Basic .NET language. The reason is that attributes are stored as metadata in the assembly. This makes them available (using a technique called reflection) both at design time in Visual Studio .NET, at compile time when the compiler can use attributes to customize the way the compiler works, and at runtime. This makes them pretty useful!
Here's a partial list of the ways that predefined attributes are used in .NET from the Microsoft documentation:
Marking methods using the WebMethod attribute in XML Web services to indicate that the method should be callable over the SOAP protocol.
Describing your assembly in terms of title, version, description, or trademark.
Describing which members of a class to serialize for persistence.
Specifying characteristics used to enforce security.
Controlling optimizations by the just-in-time (JIT) compiler so the code remains easy to debug.
Page 4 - An Example: Custom Attributes
Since Microsoft did all the coding for the .NET predefined attributes, using them is pretty simple. You just include them in front of the target as shown above. Creating your own attributes is another thing entirely because you have to do all that coding. In fact, .NET makes it a lot easier than it ever was before, but it can still be tricky.
We're going to show you how to create an attribute and then use it in another program. The program that will use this information is a very simple version of something that might evaluate customer accounts to determine, for example, suitability for a loan. Here's the form that will display the results.
To create the attributes, we use a simple class. Note that the predefined .NET attribute AttributeUsage is required to tell .NET that this is an attribute and not just another class. There are three arguments that can be used but only the first (AttributeTargets) is required:
Inherited := boolean,
AllowMultiple := boolean)>
In our simple example, we only allow other classes to be a target of our custom attribute.
Our class also has one property - Risk - and this will be the value that we use in the textboxes in our form. Notice that it's coded just like any other property.
Public Class AccountRiskFactorAttribute
Private _risk As String
Public Sub New(ByVal Value _
_risk = Value
Public ReadOnly Property Risk() _
Since our new AccountRiskFactorAttribute can only be applied to classes, let's code a few with different values of the Risk property.
Public Class BlueChip
Public Class Moderate
Public Class PoisonPeople
Notice that in this example, I deliberately coded one without the trailing qualifier 'Attribute' as part of the name; one with no attribute; and one with the trailing qualifier 'Attribute' just to try out several options that VB .NET makes available to you. (They have been displayed in bold to help you find them in the code.) In the next code example, notice that it works anyway. This is just a convenience that .NET provides. (Which, in my opinion, is not really a convenience since it just allows one more thing to confuse people who don't know about it. VB .NET has cleaned up a lot of the ambiguity that was in VB 6, but here Microsoft introduced a brand new ambiguity.) The Moderate class with no attribute will receive a default attribute value in the next code example.
Public Class RiskValue
Public Overridable ReadOnly Property _
RiskVal() As String
Dim t As Type = _
Dim a As Attribute
For Each a In _
Dim AcctRisk As _
AcctRisk = _
Catch e As Exception
' Return the middle value
' if no other value is returned
Finally, after all this preparation work, the code that actually uses these new custom attributes. It's pretty simple, since the hard part has already been done. To keep things simple, the textboxes in the form are simply updated during the form Load event. Remember to add a reference to CustomAttributes in the References section of Solution Explorer.
Public Class CustomAttributes
#Region " Windows Form Designer generated code "
Private Sub CustomAttributes_Load( _
ByVal sender As System.Object, _
ByVal e As System.EventArgs) _
Dim BlueChipRisk As New BlueChip
Dim ModerateRisk As New Moderate
Dim PoisonPeopleRisk As New PoisonPeople
BlueChipRiskVal.Text = BlueChipRisk.RiskVal()
ModerateRiskVal.Text = ModerateRisk.RiskVal()
PoisonPeopleRiskVal.Text = PoisonPeopleRisk.RiskVal()
This results in the completed form as shown. This example is obviously not 'production quality' because the goal has been to show how custom attributes are created, managed, and used in a program. The Reflection class in VB .NET offers even more ways to use attributes and even gives you the ability (using the Reflection.Emit namespace) to use attributes to create and run new executable code at runtime.
But that's a topic for another article!
** END OF ARTICLE **