<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Nullschool &#187; Visual Basic</title>
	<atom:link href="http://journal.nullschool.net/category/all/visual-basic/feed/" rel="self" type="application/rss+xml" />
	<link>http://journal.nullschool.net</link>
	<description>Cameron Beccario's Journal</description>
	<lastBuildDate>Sun, 25 May 2008 20:37:42 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8.4</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>LateCType: a strongly-typed latebound conversion operator</title>
		<link>http://journal.nullschool.net/2005/08/04/latectype-a-strongly-typed-latebound-conversion-operator/</link>
		<comments>http://journal.nullschool.net/2005/08/04/latectype-a-strongly-typed-latebound-conversion-operator/#comments</comments>
		<pubDate>Thu, 04 Aug 2005 07:12:00 +0000</pubDate>
		<dc:creator>cambecc</dc:creator>
				<category><![CDATA[All]]></category>
		<category><![CDATA[Visual Basic]]></category>

		<guid isPermaLink="false">http://ben.asmallorange.com/~cambecc/journal/2005/08/04/latectype-a-strongly-typed-latebound-conversion-operator/</guid>
		<description><![CDATA[In my last post, I discussed how to use Microsoft.VisualBasic.CompilerServices.Conversions.ChangeType to perform latebound conversions. In this post, I will take its usage a step further and show how to define a strongly-typed but latebound conversion operator.
Conversion operators in VB (generally) perform conversions on compile-time types and give strongly-typed results. ChangeType , on the other hand, [...]]]></description>
			<content:encoded><![CDATA[<p>In my <a href="http://journal.nullschool.net/2005/07/22/late-bound-conversions-with-changetype/">last post</a>, I discussed how to use Microsoft.VisualBasic.CompilerServices.Conversions.ChangeType to perform latebound conversions. In this post, I will take its usage a step further and show how to define a strongly-typed but latebound conversion operator.</p>
<p>Conversion operators in VB (generally) perform conversions on compile-time types and give strongly-typed results. <a href="http://journal.nullschool.net/2005/07/22/late-bound-conversions-with-changetype/">ChangeType </a>, on the other hand, performs conversions on types determined at run-time and returns Object. If we blend these two concepts, we can achieve some surprisingly useful behavior:</p>
<p><code> Shared Function LateCType(Of T)(ByVal Value As Object) As T</code></p>
<p><code>     Return CType(Conversions.ChangeType(Value, GetType(T)), T)</code></p>
<p><code> End Function</code></p>
<p>LateCType is a generic function that converts the parameter <em>Value</em> into an object of type T. The conversion is performed with ChangeType using T and <em>Value</em>&#8217;s type at run-time to resolve the conversion path. ChangeType returns an Object, so we must cast down to T to obtain a strongly-typed result. Because LateCType is generic, this one function can be used for any strongly-typed T that we require. For example:</p>
<p><code>     Dim i As Integer = LateCType(Of Integer)(o)</code></p>
<p><code>     Dim c As Class1 = LateCType(Of Class1)(o)</code></p>
<p><code>     Dim q As List(Of String) = LateCType(Of List(Of String))(o)</code></p>
<p>In other words, this is a strongly-typed latebound conversion operator.</p>
<p>Why is this useful? Say I have a class &#8216;Base&#8217; with a derived class &#8216;Derived&#8217; and that both convert to String:</p>
<p><code> Class Base</code></p>
<p><code>     Shared Narrowing Operator CType(ByVal Value As Base) As String</code></p>
<p><code>         Return "mars"</code></p>
<p><code>     End Operator</code></p>
<p><code> End Class</code></p>
<p><code> Class Derived : Inherits Base</code></p>
<p><code>     Shared Narrowing Operator CType(ByVal Value As Derived) As String</code></p>
<p><code>         Return "jupiter"</code></p>
<p><code>     End Operator</code></p>
<p><code> End Class</code></p>
<p>Now if I have a variable of type Base and convert it to String using CType, class Base&#8217;s conversion operator will be called:</p>
<p><code>         Dim b As Base = New Derived</code></p>
<p><code>         Debug.WriteLine(CType(b, String))</code></p>
<p>This code snippet will print &#8220;mars&#8221; even though b contains an instance of Derived. Why? Because CType uses the source and target types as they are at compile time: Base and String. Therefore, it picks Base&#8217;s conversion operator. Using LateCType however, the results are different:</p>
<p><code>         Debug.WriteLine(LateCType(Of String)(b))</code></p>
<p>This code snippet will print &#8220;jupiter&#8221; because b contains an instance of Derived at run-time, and it is this type which used by LateCType to resolve and perform the conversion. Note that the result is a strongly-typed String expression even though the conversion is latebound.</p>
<p>You might think the example above is not particularly compelling. I agree. So let&#8217;s now consider using LateCType in a different context. Generic type parameters seem to have very similar properties to LateCType: strongly-typed yet resolved at run-time. It&#8217;s no surprise then that LateCType is particularly well suited for doing conversions on generic type parameters.</p>
<p>For example, here&#8217;s a generic class which represents a space-delimited pair of values:</p>
<p><code> Public Class DelimitedPair(Of L, R)</code></p>
<p><code>     Private m_Left As L</code></p>
<p><code>     Private m_Right As R</code></p>
<p><code>     Private Const Delimiter As Char = " "c</code></p>
<p><code>     Shared Narrowing Operator CType(ByVal Value As String) As DelimitedPair(Of L, R)</code></p>
<p><code>         'TODO: Error checking.</code></p>
<p><code>         Dim Components As String() = Value.Split(Delimiter)</code></p>
<p><code>         Dim Result As New DelimitedPair(Of L, R)</code></p>
<p><code>         Result.m_Left = LateCType(Of L)(Components(0))</code></p>
<p><code>         Result.m_Right = LateCType(Of R)(Components(1))</code></p>
<p><code>         Return Result</code></p>
<p><code>     End Operator</code></p>
<p><code>     Shared Narrowing Operator CType(ByVal Value As DelimitedPair(Of L, R)) As String</code></p>
<p><code>         'TODO: Error checking.</code></p>
<p><code>         Return _</code></p>
<p><code>             LateCType(Of String)(Value.m_Left) &#038; _</code></p>
<p><code>             Delimiter &#038; _</code></p>
<p><code>             LateCType(Of String)(Value.m_Right)</code></p>
<p><code>     End Operator</code></p>
<p><code>     Public Overrides Function ToString() As String</code></p>
<p><code>         Return CStr(Me)</code></p>
<p><code>     End Function</code></p>
<p><code> End Class</code></p>
<p>Notice the use of LateCType to cast to and from the type parameters L and R. Depending on the types used to instantiate this class, the appropriate conversion operators will be called (assuming of course that those types convert to/from String). For example:</p>
<p><code>         Dim x As DelimitedPair(Of Double, Date)</code></p>
<p><code>         x = CType("23.766 1/1/2005", DelimitedPair(Of Double, Date))</code></p>
<p><code>         Debug.Print(CStr(x))</code></p>
<p>This outputs:</p>
<p><code> 23.766 2005/01/01</code></p>
<p>So going back to the dataset example from the <a href="http://journal.nullschool.net/2005/07/22/late-bound-conversions-with-changetype/">previous post</a>, we can build columns with types such as DelimitedPair where the user-input will be validated and converted automatically even though the underlying types are quite complex:</p>
<p><code> Module Example1</code></p>
<p><code>     Sub Main()</code></p>
<p><code>         'First create a dataset to work with.</code></p>
<p><code>         Dim Patients As New DataSet("Patients")</code></p>
<p><code>         Dim ContactInfo As DataTable = Patients.Tables.Add("ContactInfo")</code></p>
<p><code>         ContactInfo.Columns.Add("Age", GetType(Integer))</code></p>
<p><code>         ContactInfo.Columns.Add("Weight", GetType(SqlTypes.SqlDouble))</code></p>
<p><code>         ContactInfo.Columns.Add( _</code></p>
<p><code>             "LastPayment", _</code></p>
<p><code>             GetType(DelimitedPair(Of Date, Decimal)))</code></p>
<p><code>         'Next, call a generalized function to add a row to the dataset.</code></p>
<p><code>         AddRow(ContactInfo, "29", "63.4", "8/3/2005 1076.43")</code></p>
<p><code>         'Lastly, print out the results.</code></p>
<p><code>         For Each Value As Object In ContactInfo.Rows(0).ItemArray</code></p>
<p><code>             Debug.WriteLine(Value.ToString &#038; " : " &#038; Value.GetType.ToString)</code></p>
<p><code>         Next</code></p>
<p><code>     End Sub</code></p>
<p><code>     ...</code></p>
<p>Running this code (see previous post) will give the result:</p>
<p><code> 29 : System.Int32</code></p>
<p><code> 63.4 : System.Data.SqlTypes.SqlDouble</code></p>
<p><code> 2005/08/03 1076.43 : Example2+DelimitedPair`2[System.DateTime,System.Decimal]</code></p>
<p>Pretty cool.  So the choice is up to us, the programmers, to use either early-bound or late-bound conversions where late-bound conversions seem particularly well suited for use on generic type parameters. Again, there is a performance penalty for doing late-bound conversions and you wouldn&#8217;t want to run them in a tight-loop. For user-driven input however, no problem.</p>
]]></content:encoded>
			<wfw:commentRss>http://journal.nullschool.net/2005/08/04/latectype-a-strongly-typed-latebound-conversion-operator/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Late-bound conversions with ChangeType</title>
		<link>http://journal.nullschool.net/2005/07/22/late-bound-conversions-with-changetype/</link>
		<comments>http://journal.nullschool.net/2005/07/22/late-bound-conversions-with-changetype/#comments</comments>
		<pubDate>Fri, 22 Jul 2005 11:46:29 +0000</pubDate>
		<dc:creator>cambecc</dc:creator>
				<category><![CDATA[All]]></category>
		<category><![CDATA[Visual Basic]]></category>

		<guid isPermaLink="false">http://ben.asmallorange.com/~cambecc/journal/2005/07/22/late-bound-conversions-with-changetype/</guid>
		<description><![CDATA[I was reading Paul Vick&#8217;s entries (1) (2) on dynamism, and it reminded me of a problem I encountered a short time ago.
Lately, I&#8217;ve been working with datasets and validation of user-supplied data. This data, entered as strings into bound controls, requires validation to make sure it converts to the underlying field types. Perhaps it&#8217;s [...]]]></description>
			<content:encoded><![CDATA[<p>I was reading Paul Vick&#8217;s entries <a href="http://www.panopticoncentral.net/archive/2005/07/08/10032.aspx">(1)</a> <a href="http://www.panopticoncentral.net/archive/2005/07/21/10181.aspx">(2)</a> on dynamism, and it reminded me of a problem I encountered a short time ago.</p>
<p>Lately, I&#8217;ve been working with datasets and validation of user-supplied data. This data, entered as strings into bound controls, requires validation to make sure it converts to the underlying field types. Perhaps it&#8217;s my novice-level experience, but doing validation like this is a real pain.</p>
<p>The problem is that at some point the inputted string has to be converted to the underlying type U. To be robust, this conversion code requires as many unique code paths as there are possibilities for U. Looking only at the types allowed by the XSD designer, that&#8217;s 17 possibilities: Boolean, SByte, Byte, Short, UShort, Integer, UInteger, Long, ULong, Decimal, Single, Double, Date, Char, String, TimeSpan, and Guid. The corresponding conversion code paths need to be somewhere, whether written by hand or contained in a self-validating control. But consider that U could be one of the Sql types, such as SqlInt32, or one of the new Nullable types, such as Nullable(Of Integer), or even a user-defined type. The possibilities for U are theoretically limitless, and it&#8217;s unlikely that specialized, hand-written code or self-validating controls purchased from a vendor can handle data validation in these situations. Furthermore, I have yet to find self-validating controls that offer robust error handling capabilities, like the ability to display localized error messages or to throw richly-typed exceptions with detailed context information. In the end you&#8217;re left with the only option being a hand-written, and expensive, validation mechanism. So what to do?</p>
<p>There&#8217;s another place where these conversion code paths are written, and that&#8217;s in the Visual Basic runtime. Why not use them? They are contained in a &#8220;hidden&#8221; VB runtime function that can perform latebound conversions: Microsoft.VisualBasic.CompilerServices.Conversions.ChangeType. We will create generalized code using this function to do all type validation at runtime. In other words, we will defer all type validation to the latebinder. Consider the following code:</p>
<p><code>Module Example1</code><br />
<code>    Sub Main()</code></p>
<p><code>         'First create a dataset to work with.</code></p>
<p><code>         Dim Patients As New DataSet("Patients")</code></p>
<p><code>         Dim ContactInfo As DataTable = Patients.Tables.Add("ContactInfo")</code></p>
<p><code>         ContactInfo.Columns.Add("Age", GetType(Integer))</code></p>
<p><code>         ContactInfo.Columns.Add("Weight", GetType(SqlTypes.SqlDouble))</code></p>
<p><code>         ContactInfo.Columns.Add("LastVisit", GetType(Nullable(Of Date)))</code></p>
<p><code>          'Next, call a generalized function to add a row to the dataset.</code></p>
<p><code>         AddRow(ContactInfo, "29", "63.4", "6/2/2005")</code></p>
<p><code>          'Lastly, print out the results.</code></p>
<p><code>         For Each Value As Object In ContactInfo.Rows(0).ItemArray</code></p>
<p><code>             Debug.WriteLine(Value.ToString &#038; " : " &#038; Value.GetType.ToString)</code></p>
<p><code>         Next</code></p>
<p><code>     End Sub</code></p>
<p><code>      Function AddRow( _</code></p>
<p><code>         ByVal Table As DataTable, _</code></p>
<p><code>         ByVal ParamArray Values As Object()) As DataRow</code></p>
<p><code>        'This function adds any values to any dataset by performing</code></p>
<p><code>         'the neccesary conversions to the underlying field types at runtime.</code></p>
<p><code>          Dim Index As Integer = 0</code></p>
<p><code>         Dim Count As Integer = Math.Min(Table.Columns.Count, Values.Length)</code></p>
<p><code>          While Index </code>&lt;<code> Count</code></p>
<p><code>              'Convert each value to the underlying field type.</code></p>
<p><code>             Values(Index) = _</code></p>
<p><code>                 CompilerServices.Conversions.ChangeType( _</code></p>
<p><code>                     Values(Index), _</code></p>
<p><code>                     Table.Columns(Index).DataType)</code></p>
<p><code>             Index += 1</code></p>
<p><code>         End While</code></p>
<p><code>        'Add the row of converted values.</code></p>
<p><code>         Return Table.Rows.Add(Values)</code></p>
<p><code>     End Function</code></p>
<p><code> End Module</code></p>
<p>Compiling and running outputs:</p>
<p><code> 29 : System.Int32</code></p>
<p><code> 63.4 : System.Data.SqlTypes.SqlDouble</code></p>
<p><code> 6/2/2005 12:00:00 AM : System.Nullable`1[System.DateTime]</code></p>
<p>This code creates a dataset with fields of type Integer, SqlDouble, and Nullable(Of Date). The user supplies the text &#8220;29&#8243;, &#8220;63.4&#8243; and &#8220;6/2/2005&#8243;, and these strings are converted into the underlying types and added into the dataset. One function, AddRow, performs most of the work. It loops through each value, converting it to the appropriate column type. If the conversion fails an exception occurs. If it succeeds for all values, a row is inserted into the table with the correctly converted values. Notice that we can&#8217;t use a normal CType operator because it requires the type of the column to be known at compile-time. Also notice that column types such as SqlDouble and Nullable(Of Date) work correctly. These types rely on operator overloading for conversions, which means that Conversions.ChangeType is performing operator overload resolution at runtime and invoking the appropriate methods.</p>
<p>Actually, the .Net framework has a function which gets us partially towards a solution: System.Convert.ChangeType(value As Object, conversionType As System.Type). The documentation is quite vague, but this function also makes latebound conversions. Unfortunately, System.Convert.ChangeType supports only core conversions of the .Net world, such as along lines of inheritance and between intrinsics. It does not perform operator overload resolution and therefore does not offer a complete solution. For example, it could not handle SqlDouble or Nullable(Of Date) fields.</p>
<p>Why Visual Basic&#8217;s ChangeType is &#8220;hidden&#8221; in the CompilerServices namespace rather than exposed as a full fledged member of the language is an uninteresting story, but basically I lost that argument and it remains hidden and &#8220;unsupported&#8221;. Thankfully, it&#8217;s Public because the compiler needs to generate calls to it in certain scenarios (such as the copy-out conversion of an argument to a late-bound call), meaning it&#8217;s callable from user-code.</p>
<p>I&#8217;ve been reading in the documentation that handling the Format and Parse events of a Binding object allows custom data conversions between datasets and bound controls (see <a href="ms-help://MS.VSCC.v80/MS.MSDNQTR.v80.en/MS.MSDN.v80/MS.NETDEV.v10.en/dnpag/html/scag-ch02.htm">here</a> if you have VS 2005 Beta2 installed). By using ChangeType, we need only one 1-line function to handle both of these events for all controls in the program. Add these lines to the end of Sub Main (assumes a form called InfoForm with a WeightTextBox control and a button control):</p>
<p><code>        'Create a binding between the dataset and the TextBox control.</code></p>
<p><code>         Dim InfoEntry As New InfoForm</code></p>
<p><code>         Dim Binding As Windows.Forms.Binding = _</code></p>
<p><code>             New Windows.Forms.Binding("Text", Patients, "ContactInfo.Weight")</code></p>
<p><code>        'Hook-up the binding events with a generalized converter function.</code></p>
<p><code>         AddHandler Binding.Format, AddressOf Convert</code></p>
<p><code>         AddHandler Binding.Parse, AddressOf Convert</code></p>
<p><code>         InfoEntry.WeightTextBox.DataBindings.Add(Binding)</code></p>
<p><code>         'Display the form.</code></p>
<p><code>         System.Windows.Forms.Application.Run(InfoEntry)</code></p>
<p><code>  Now add this sub:</code></p>
<p><code>    Sub Convert( _</code></p>
<p><code>         ByVal Sender As Object, _</code></p>
<p><code>         ByVal Cevent As Windows.Forms.ConvertEventArgs)</code></p>
<p><code>          Debug.WriteLine("convert to " &#038; Cevent.DesiredType.ToString)</code></p>
<p><code>          'Use a latebound conversion to convert the incoming value into</code></p>
<p><code>         'any desired type.</code></p>
<p><code>         Cevent.Value = _</code></p>
<p><code>             CompilerServices.Conversions.ChangeType( _</code></p>
<p><code>                 Cevent.Value, _</code></p>
<p><code>                 Cevent.DesiredType)</code></p>
<p><code>     End Sub</code></p>
<p>That&#8217;s it. By using the example function above, any control can be bound to any data column (assuming the type conversion succeeds of course!). Run the code and enter some values in the textbox. You should get output similar to:</p>
<p><code> convert to System.String</code></p>
<p><code> convert to System.String</code></p>
<p><code> convert to System.Data.SqlTypes.SqlDouble</code></p>
<p><code> convert to System.String</code></p>
<p><code> convert to System.Data.SqlTypes.SqlDouble</code></p>
<p><code> convert to System.String</code></p>
<p>I only wish I was using Visual Studio 2005 at work. Code like this would make my life so much easier.  Three words of caution:</p>
<ol>
<li>ChangeType only does type validation, not value validation such as checking for negative weight or other invalid values. You still have to write or purchase this code.</li>
<li>ChangeType costs execution time because it is latebound. But keep in mind that we&#8217;re validating user-entered code here. The cost of calling ChangeType is miniscule compared to the time it takes the user to lift their finger from the Enter key.</li>
<li>ChangeType is supposed to be &#8220;hidden&#8221;. It is not a first-class member of the Visual Basic language.</li>
</ol>
<p>In my next post I will take the usage of ChangeType further and show how it can be applied to Generic type parameters to provide even more generalization.</p>
]]></content:encoded>
			<wfw:commentRss>http://journal.nullschool.net/2005/07/22/late-bound-conversions-with-changetype/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>useful IIf for Visual Basic 2005</title>
		<link>http://journal.nullschool.net/2005/06/08/useful-iif-for-visual-basic-2005/</link>
		<comments>http://journal.nullschool.net/2005/06/08/useful-iif-for-visual-basic-2005/#comments</comments>
		<pubDate>Tue, 07 Jun 2005 16:00:34 +0000</pubDate>
		<dc:creator>cambecc</dc:creator>
				<category><![CDATA[All]]></category>
		<category><![CDATA[Visual Basic]]></category>

		<guid isPermaLink="false">http://ben.asmallorange.com/~cambecc/journal/2005/06/08/useful-iif-for-visual-basic-2005/</guid>
		<description><![CDATA[The IIf statement in Visual Basic is a pain when Option Strict is on. The reason is that the return value is Object and thus requires a cast back to the target type:
&#160;&#160;&#160;&#160;Dim a As Integer = IIf(SomeCondition(), 10, 20)
&#160;&#160;&#160;&#160;Error:  Option Strict On disallows implicit conversions from 'System.Object' to 'Boolean'.
To fix the compile error, [...]]]></description>
			<content:encoded><![CDATA[<p>The IIf statement in Visual Basic is a pain when <code>Option Strict</code> is on. The reason is that the return value is <code>Object</code> and thus requires a cast back to the target type:</p>
<p><code>&nbsp;&nbsp;&nbsp;&nbsp;Dim a As Integer = IIf(SomeCondition(), 10, 20)<br />
&nbsp;&nbsp;&nbsp;&nbsp;Error:  Option Strict On disallows implicit conversions from 'System.Object' to 'Boolean'.</code></p>
<p>To fix the compile error, you need to add a cast:</p>
<p><code>&nbsp;&nbsp;&nbsp;&nbsp;Dim a As Integer = CInt(IIf(SomeCondition(), 10, 20))</code></p>
<p>Even worse, use an enum:</p>
<p><code>&nbsp;&nbsp;&nbsp;&nbsp;Dim b As Color = CType(IIf(SomeCondition(), Color.Red, Color.Blue), Color)</code></p>
<p>But by using generic methods and type inferencing, you can create a version of IIf that eliminates the need for the cast:</p>
<p><code>&nbsp;&nbsp;&nbsp;&nbsp;Function IIf(Of T)(ByVal Expression As Boolean, ByVal TruePart As T, ByVal FalsePart As T) As T<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;If Expression Then Return TruePart Else Return FalsePart<br />
&nbsp;&nbsp;&nbsp;&nbsp;End Function</code></p>
<p>Then the above examples could be written as:</p>
<p><code>&nbsp;&nbsp;&nbsp;&nbsp;Dim a As Integer = IIf(SomeCondition(), 10, 20)<br />
&nbsp;&nbsp;&nbsp;&nbsp;Dim b As Color = IIf(SomeCondition(), Color.Red, Color.Blue)</code></p>
<p>Much nicer. And also much faster because we avoid boxing the parameters and unboxing the result. Now if only IIf could be massaged into a real ternary operator&#8230;</p>
]]></content:encoded>
			<wfw:commentRss>http://journal.nullschool.net/2005/06/08/useful-iif-for-visual-basic-2005/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
	</channel>
</rss>
