RSS feed blog search engine
 

@ Head  
Released:  3/7/2009 5:07:48 PM  
RSS Link:  http://msmvps.com/bill/Rss.aspx  
Last View 2/10/2012 9:53:05 PM  
Last Refresh 2/10/2012 4:41:54 PM  
Page Views 185  
Comments:  Read user comments (0)  
Report violation Report a violation or adult content
Save It  



Description:



Bill's random thoughts...


Contents:

VB Quark #7 : Optional Parameters and Dates

Hopefully you already know VB has full support for Optional parameters, both declaring them and calling them, but did you know you can use Dates as Optional parameters ?

   Public Sub AddNewCustomer(customer As Customer
                            
Optional dateAdded As Date = Nothing
)
     
If dateAdded = Nothing Then dateAdded = Now

 

VB has had this support for Optional parameters in place for the last decade or so in .NET and for years before that back in the COM versions of VB.

In the last release of .NET (VS 2010), C# finally got support for Optional parameters, so the above in C# would look like:

     public void AddNewCustomer(Customer customer, 
                          
DateTime dateAdded = default(DateTime
))
      {
        
if (dateAdded == default(DateTime)) dateAdded = DateTime.Now;

 

The Nothing in the VB declaration is the same as default(DateTime) in C#, which equates to the theoretical Gregorian date of 1/1/0001.

But what if you want to specify a default date ? Well because VB supports date literals, in VB you can, but in C# you cant.  In VB you can write any date literal for the optional parameter value. For example, you might have some legacy database support, and when the date is unknown you want to use the equivalent of an OLE Dates zero value:

  Public Sub AddNewCustomer(customer As Customer,
                            
Optional dateAdded As Date = #12/30/1899#)

 

When the VB compiler compiles this, it adds a System.Runtime.CompilerServices.DateTimeConstantAttribute to the parameter information with the default value stored as an Int64 (the number of ticks). C# actually sees the optional value in the above example and will use it. That is both VB and C# can call the code taking advantage of the optional value for the date parameter, but only VB lets you define that value.




Displaying Dates in VS 2010

From time to time there’s discussion about the way dates are displayed in the Visual Studio IDE for Visual Basic. Typically dates are shown using VB’s date literal syntax of #MM/dd/yyyy# which is the standard US format.  For people outside of the USA this can be confusing or ambiguous at times.  The good news is Visual Studio allows you to easily add your own display formatter.

Simply create a new class library project, add the following attribute to your AssemblyInfo file:

<Assembly: DebuggerDisplay("Date: {ToString(""s"")}   kind={Kind}", Target:=GetType(DateTime))>

And then just copy the assembly to your Visualizers directory, eg:
  My DocumentsVisual Studio 2010Visualizers

I added the Kind property to the display so as you can easily see if the Date is a local date, UTC or unspecified.

I've attached a sample project.  Enjoy Smile

 




VB Quark #6: Date operators

The DateTime structure in .NET includes custom operators for Date comparisons such as less than, greater than, equal and not equal; but did you know it also includes addition and subtraction operators ?  Theres two subtraction operators and one addition operator defined inside DateTime:

  • date = date timespan
  • timespan = date date
  • date = date + timespan

Those three cases should all seem relatively obvious, such as adding or subtracting an hour from a date, or calculating how many minutes between two dates etc...

BUT, did you know VB also defines another case where you can add two dates, eg:

     Dim result = Date1 + Date2

Now if you guessed that the type of result is String, then congratulations !! Note: this operator resolution is only valid with Option Strict Off

Obviously adding two dates cant give a valid date or timespan, so the only real options are to return a string concatenation of the date or throw an error. There are a couple of fringe cases where, depending on your system locale, the resultant string can indeed be parsed back into a date, eg:

      Dim dt1 = #1:00:00 PM#
     
Dim
dt2 = Now.Date
     
Dim dtResult As Date = dt1 + dt2

But that really is a fringe case, and would depend on the system locale formatting.

I think its probably fair to say this case is a quirk of a quark, probably introduced as partial legacy. I honestly cant see any usefulness of the addition operator between two dates that returns a string. If the intent was some legacy support, it might have made sense to return a date if one of the dates was date zero with time information, but the concatenation of the date strings doesnt seem to reliably serve any purpose.

The good news is you can only do the string = date + date operation with Option Strict Off. Guess thats just another reason to turn Option Strict On  Winking smile




VB Quark #5: C is for Char

Can you pick the problem with this code ? :

      Dim currentChar As Char

      For i = 0 To
largenumber
         currentChar = getChar(i)
        
If currentChar = "a" Then
            count += 1
        
End If
     
Next

 

The answer of course is the literal a is of type string, not of type Char. Hence currentChar gets implicitly widened to a String to make the expression a string comparison expression. This means a new string is created with the contents of currentChar on each iteration, and the comparison is a string comparison which checks for null strings and empty strings and then does a compare ordinal etc. This is incredibly inefficient.

If a was typed as Char, then the comparison is a simple low level IL compare of the underlying values (int16s).

You can use CChar, as in CChar(a), but its a lot easier just to add the type literal suffix c, eg ac

      Dim currentChar As Char

      For i = 0 To
largenumber
         currentChar = getChar(i)
        
If currentChar = "a"c Then
            count += 1
        
End If
     
Next

The change in this code is about 20 fold performance improvement (run as release build outside of Visual Studio). Thats a 20 fold increase just by typing one extra letter !!

This example was based on real sample code where a massive file was being parsed char by char.  There too, attention to the fine detail showed a massive performance improvement over the original code. Its often the little things that can make a huge difference.

 

This VB quark was brought to you by the type literal c




VB Quark #4: type literals

Do you know why you cant write this code in VB:

   Dim x = 123456789.0123456789

Answer: The IDE wont let you Winking smile

If you try to write that code the IDE will truncate the number, giving :

   Dim x = 123456789.01234567

To include all the decimal places you need to be using the Decimal type. To do this you indicate the constant is of type decimal by adding the suffix D on the end, eg:

   Dim x = 123456789.0123456789D

The reason for this is VB treats numeric literals as of type Double by default if they have a decimal place. If there is no decimal place in the literal then the value is consider to be an Integer (Int32), or if it is too large for an Integer, its considered to be a Long (Int64).

If you want the literal as a type other than Double, Integer or Long you need to either convert using CType, CShort, CSng etc, or add a type literal suffix. The following is the complete list for numeric type literal suffixes in VB:

Suffix Type
F Single
R Double
D Decimal
S Int16, Short
I Int32, Integer
L Int64, Long
US UInt16, UShort
UI UInt32, UInteger
UL UInt64, ULong

In case youre wondering, the F for Single is short for "Float, and the R for Double is short for Real Number.

Heres another example of where you should use type literal suffixes. Consider this code :

      Dim i1, i2 As Int16
      i1 = &HF0
      i2 = i1
And &HFF

If you have Option Strict On, the last line will cause a compile time error saying that an implicit conversion from Integer to Short is not allowed. So what is happening here, and why doesnt the middle line cause the same problem ?

Well the line i1 = &HF0 compiles fine because the constant &HF0 can be evaluated at compile time, so theres no problem there. The last line however cannot be evaluated because the variable i1 is not a constant. Try it for yourself if you like: change the declaration of i1 to a Const, and youll see the last line  compiles fine with Strict On.

Because VB cant evaluate the variable expression at compile time, it uses the default type for numeric constants : Integer (aka Int32). And because a short can be implicitly widened to Int32, the expression on the right hand side becomes an Int32: hence the error.

In Visual Studio the error correction wizard will suggest converting the entire  expression to an Int16, as such :

      i2 = CShort(i1 And &HFF)

But thats a runtime conversion that isnt needed if you declare the &HFF constant with the correct type literal suffix S:

      i2 = i1 And &HFFS

As you can see, the code correction wizard in Visual Studio doesnt always provide the best syntax to use, so it really is up to you to know the correct literals to use and apply them. 

Oh, you may have also noticed there is no type literal suffix for Byte and SByte. Ill leave that for yet another quark Smile




VB Quark #3: operator differences in VB/C#

Can you spot the problem with this code:

   <Extension()>
  
Public Function ToColor(argb As UInteger) As Color
      Return Color
.FromArgb( _
                     
CType((argb & &HFF000000) >> &H18, Byte
), _
                     
CType((argb & &HFF0000) >> &H10, Byte
), _
                     


Home  
 
 




Privacy Policy