|
Dit artikel is gepubliceerd op zondag 31 juli 2011 op vbvoorbeelden, bezoek de website voor een recente versie van dit artikel of andere artikels.
Attributen kunnen ook zelf gedefinieerd worden. Dit is een vrij eenvoudig werkje, je maakt een eigen attribuutklasse die je doet overerven van de Attribute klasse. Deze attribuutklasse kan dan gebruikt worden om metadata aan een definitie toe te voegen.
Het is voor de leesbaarheid aan te raden de "Attribute" suffix te gebruiken in de identifier van de attribuutklasse.
Bij de definitie van die klasse plaats je een AttributeUsage attribuut, daar geef je als argumentwaarde een AttributeTargets enumeratiewaarde aan de constructor door om op te geven op welke entiteit de attribuut slaat. Mogelijkheden zijn : All, Assembly, Class, Constructor, Delegate, Enum, Event, Field, Interface, Method, Module, Parameter, Property, ReturnValue en Struct. Het zou ook mogelijk zijn om AttributeTargets.Constructor Or AttributeTargets.Method Or AttributeTargets.Property in te stellen. Dit zou dus bruikbaar zijn om aan te geven dat het attribuut van toepassing kan zijn op de entiteiten constructor, method en/of property.
Het AttributeUsage attribute is dus bruikbaar om bij het definiëren van een attribuutklasse aan te geven waarop het attribuut dat je aan het definiëren bent van toepassing zal zijn.
De volgende argumentwaarden die hier in de voorbeelden lijken doorgegeven te worden aan de constructor van de AttributeUsage klasse zijn eigenlijk geen argumentwaarden. Ze zijn gewoon een verkorte taalconstructie ( met een toekenning via de operator := ) om hier meteen na het instantiëren van dat attribuut de eigenschappen AllowMultiple en Inherited van de AttributeUsage klasse op een bepaalde waarde in te stellen.
AllowMultiple kan je op True instellen als het attribuut dat je aan het definiëren bent meerder keren kan gebruikt worden op de entiteit(en) die ervoor is/zijn opgegeven. By default kan een attribuut maar één keer worden toegepast.
Inherited kan je op False instellen als je wenst dat het attribuut dat je aan het definiëren bent niet zal worden overgeërfd naar subklassen van de klasse waarbij dat attribuut zal gedefinieerd worden. By default worden attributen overgeërfd.
Bij het definiëren van de constructor van een attribuutklasse ben je beperkt in de mogelijke datatypes voor de parameters van die constructor, namelijk : Byte, Short, Integer, Long, Single, Double, Char, String, Boolean, Type of eender welk enumeratietype. Dit omdat enkele deze geserialiseerd kunnen worden in de metadata voor de assembly.
Via reflection kan de aan de klasse of aan de members toegevoegde metadata vervolgens weer worden opgespoord en vervolgens op de één of andere manier gebruik van worden gemaakt. Het opsporen van attributen kan bijvoorbeeld via de classmembers GetCustomAttribute en GetCustomAttributes methods van de Attribute klasse. Visual Basic 2010 Broncode <AttributeUsage(AttributeTargets.Class, AllowMultiple:= True, Inherited:= False)> _ Public Class HistoryAttribute : Inherits Attribute : Implements IComparable Public m_Date As String Public Property [Date]() As String Get [Date] = m_Date End Get Set( ByVal value As String) m_Date = value End Set End Property Private m_Author As String Public Property Author() As String Get Author = m_Author End Get Set( ByVal value As String) m_Author = value End Set End Property Private m_Change As String Public Property Change() As String Get Change = m_Change End Get Set( ByVal value As String) m_Change = value End Set End Property Public Sub New( ByVal [date] As String, _ ByVal author As String, ByVal change As String) Me.Date = [date] Me.Author = author Me.Change = change End Sub Public Function CompareTo( ByVal obj As Object) As Integer _ Implements System.IComparable. CompareTo If TypeOf obj Is HistoryAttribute Then Dim ha As HistoryAttribute = DirectCast(obj, HistoryAttribute) Return [Date].CompareTo(ha.Date) End If End FunctionEnd ClassPublic Class ClassInfo Public Shared Function GetHistory( ByVal type As Type) As String Dim historyAttributes As HistoryAttribute() = _ DirectCast(Attribute.GetCustomAttributes(type, GetType(HistoryAttribute)), _ HistoryAttribute()) GetHistory &= "fullname : " & type.FullName & _ Environment.NewLine() & Environment.NewLine() & _ "history : " & Environment.NewLine() Array.Sort(historyAttributes) For Each historyAttribute As HistoryAttribute In historyAttributes GetHistory &= " date : " & historyAttribute.Date.ToString() & " - " & _ "author : " & historyAttribute.Author & _ Environment.NewLine() & _ " change : " & historyAttribute.Change & _ Environment.NewLine() & Environment.NewLine() Next End FunctionEnd Class<History( "2008-02-21", "John", "Created this class."), _ History( "2008-02-22", "Jane", "Added Method1."), _ History( "2008-02-23", "John", "Corrected Method1."), _ History( "2008-02-24", "Paul", "Added Method2.")> _ Class Class1 Public Sub Method1() Console.WriteLine( "method1") End Sub Public Sub Method2() Console.WriteLine( "method2") End SubEnd ClassClass Example1 Public Shared Sub Main() Console.WriteLine(ClassInfo.GetHistory( GetType( Class1))) Console.ReadLine() End SubEnd ClassDownload Visual Basic 2010 Broncode Download Visual C# Sourcecode
Console Application Output fullname : ContentConsoleApplication.Class1
history :
date : 2008-02-21 - author : John
change : Created this class.
date : 2008-02-22 - author : Jane
change : Added Method1.
date : 2008-02-23 - author : John
change : Corrected Method1.
date : 2008-02-24 - author : Paul
change : Added Method2. Een ander voorbeeld : Visual Basic 2010 Broncode Public Class ContractAttribute : Inherits Attribute Private ReadOnly m_Text As String Public ReadOnly Property Text() As String Get Text = m_Text End Get End Property Public Sub New( ByVal text As String) m_Text = text End SubEnd Class<AttributeUsage(AttributeTargets.All, AllowMultiple:= False, Inherited:= False)> _ Public Class SummaryAttribute : Inherits ContractAttribute Public Sub New( ByVal text As String) MyBase.New( text) End SubEnd Class<AttributeUsage(AttributeTargets.Class, AllowMultiple:= True, Inherited:= True)> _ Public Class InvariantAttribute : Inherits ContractAttribute Public Sub New( ByVal text As String) MyBase.New( text) End SubEnd Class<AttributeUsage(AttributeTargets.Constructor Or AttributeTargets.Method Or _ AttributeTargets.Property, _ AllowMultiple:= True, Inherited:= False)> _ Public Class PreConditionAttribute : Inherits ContractAttribute Public Sub New( ByVal text As String) MyBase.New( text) End SubEnd Class<AttributeUsage(AttributeTargets.Constructor Or AttributeTargets.Method Or _ AttributeTargets.Property, _ AllowMultiple:= True, Inherited:= False)> _ Public Class PostConditionAttribute : Inherits ContractAttribute Public Sub New( ByVal text As String) MyBase.New( text) End SubEnd ClassPartial Class ClassInfo Public Shared Function GetContract( ByVal type As Type) As String Dim summaryAttribute As SummaryAttribute = _ DirectCast(Attribute.GetCustomAttribute(type, GetType(SummaryAttribute)), _ SummaryAttribute) Dim invariantAttributes As InvariantAttribute() = _ DirectCast(Attribute.GetCustomAttributes(type, GetType(InvariantAttribute)), _ InvariantAttribute()) GetContract &= "fullname : " & type.FullName & Environment.NewLine() & _ " invariants : " & Environment.NewLine() For Each invariantAttribute As InvariantAttribute In invariantAttributes GetContract &= " - " & invariantAttribute.Text & Environment.NewLine() Next Dim membersInfo As Reflection. MemberInfo() = type.GetMembers() For Each memberInfo As Reflection. MemberInfo In membersInfo If (memberInfo.MemberType = Reflection.MemberTypes.Method OrElse _ memberInfo.MemberType = Reflection.MemberTypes.Property OrElse _ memberInfo.MemberType = Reflection.MemberTypes.Constructor) AndAlso _ memberInfo.DeclaringType Is type Then GetContract &= GetContract(memberInfo) End If Next End Function Public Shared Function GetContract( ByVal member As Reflection. MemberInfo) As String GetContract &= " " & member.Name & " : " & Environment.NewLine() Dim summary As SummaryAttribute() = _ DirectCast(member.GetCustomAttributes( GetType(SummaryAttribute), False), _ SummaryAttribute()) GetContract &= " summary : " Dim summaryText As String = "-" If summary.Length > 0 Then summaryText = summary(0).Text End If GetContract &= summaryText & Environment.NewLine() Dim preConditions As PreConditionAttribute() = _ DirectCast(member.GetCustomAttributes( GetType(PreConditionAttribute), False), _ PreConditionAttribute()) GetContract &= " pre-condities : " Dim preConditionText As String For Each preCondition As PreConditionAttribute In preConditions preConditionText &= Environment.NewLine() & _ " - " & preCondition.Text Next If preConditionText = "" Then GetContract &= "-" & Environment.NewLine() Else GetContract &= preConditionText & Environment.NewLine() End If Dim postConditions As PostConditionAttribute() = _ DirectCast(member.GetCustomAttributes( GetType(PostConditionAttribute), False), _ PostConditionAttribute()) GetContract &= " post-condities : " Dim postConditionText As String For Each postCondition As PostConditionAttribute In postConditions postConditionText &= Environment.NewLine() & _ " - " & postCondition.Text Next If postConditionText = "" Then GetContract &= "-" & Environment.NewLine() Else GetContract &= postConditionText & Environment.NewLine() End If End FunctionEnd ClassClass Assertion Public Shared Sub Require( ByVal condition As Boolean) If Not condition Then Throw New PreConditionException End Sub Public Shared Sub Ensure( ByVal condition As Boolean) If Not condition Then Throw New PostConditionException End Sub Public Class PreConditionException : Inherits ApplicationException End Class Public Class PostConditionException : Inherits ApplicationException End ClassEnd Class<Summary( "Bounded LIFO collection."), _ Invariant( "GetCount() >= 0"), _ Invariant( "GetSize() >= 2")> _ Class BoundedStack Private m_Stack As Object() Private m_Size As Integer Private m_Count As Integer <Summary( "Constructor expects capacity ( size )."), _ PreCondition( "size > 1"), _ PostCondition( "GetSize() = size")> _ Public Sub New( ByVal size As Integer) Assertion.Require(size > 1) m_Size = size ReDim m_Stack(m_Size - 1) Assertion.Ensure(getSizeQuery() = size AndAlso getCountQuery() = 0) Assertion.Ensure(invariant()) End Sub <Summary( "GetSize() gets the capacity."), _ PostCondition( "GetSize() > 1")> _ Public Function GetSize() As Integer GetSize = getSizeQuery() Assertion.Ensure(GetSize > 1) Assertion.Ensure(invariant()) End Function Private Function getSizeQuery() As Integer getSizeQuery = m_Size End Function <Summary( "GetCount() gets the count."), _ PostCondition( "GetCount() >= 0"), _ PostCondition( "GetCount() <= GetSize()")> _ Public Function GetCount() As Integer GetCount = getCountQuery() Assertion.Ensure(GetCount >= 0 AndAlso GetCount <= getSizeQuery()) Assertion.Ensure(invariant()) End Function Private Function getCountQuery() As Integer getCountQuery = m_Count End Function Private Function invariant() As Boolean Return getCountQuery() >= 0 AndAlso getSizeQuery() >= 2 End Function End ClassPublic Class Example2 Public Shared Sub Main() Console.WriteLine(ClassInfo.GetContract( GetType(BoundedStack))) Console.ReadLine() End SubEnd ClassDownload Visual Basic 2010 Broncode Download Visual C# Sourcecode
Console Application Output fullname : ContentConsoleApplication.BoundedStack
invariants :
- GetCount() >= 0
- GetSize() >= 2
GetSize :
summary : GetSize() gets the capacity.
pre-condities : -
post-condities :
- GetSize() > 1
GetCount :
summary : GetCount() gets the count.
pre-condities : -
post-condities :
- GetCount() >= 0
- GetCount() <= GetSize()
.ctor :
summary : Constructor expects capacity ( size ).
pre-condities :
- size > 1
post-condities :
- GetSize() = size
Dit artikel is gepubliceerd op zondag 31 juli 2011 op vbvoorbeelden, bezoek de website voor een recente versie van dit artikel of andere artikels.
|