October 2004 - Posts

 

I’m pretty much a C# fan.  I admit it, I like semi-colons.  Frankly, I think that I’m addicted to them, and I go through withdrawal every time I find myself fumbling through Visual Basic .NET code.  I’ll find my fingers sneaking in a friendly ; .  Of course, the IDE politely reminds me that I’m an idiot.  As soon as possible after my VB.NET experience, I usually scurry back to the comfort of C#. 

 

However, there are a few things that VB.NET just does for you that C #doesn’t.  For example, take the following code C# snippet:

 

 

using System;

 

namespace Dennany.Examples.Test

{

    class MainClass

    {

        static void Main(string[] args)

        {

            Customer c = new Customer();

            c.Name = "Jerry Dennany";

            ProcessCustomer.ProcessCustomerName (ref c.Name);

        }

    }

    public class Customer

    {

        private string _name;

        public string Name

        {

            get

            {

                return _name;

            }

            set

            {

                _name = value;

            }

        }

    }

 

    public class ProcessCustomer

    {

        static public void ProcessCustomerName(ref string NameProperty)

        {

            // Do something here

        }

    }

}

 

Ahh, I’m ever so fond of closing curly brackets!

 

However, I’m less fond of the all-too-familiar blue squiggly that you’ll see at this line:

           

ProcessCustomer.ProcessCustomerName (ref c.Name);

 

If you compile, you should get the following message:

 

Error: A property or indexer may not be passed as an out or ref parameter       

 

The reason makes sense.  Really, this could only work for the get side of a property or indexer.  If the ref parameter was changed during the method’s return, there would be no way for the set operation to take place.  That’s why the compiler doesn’t allow this operation.

 

However, let’s take a look at the same code, only converted to VB.NET.  (And please, let’s not be pedantic about the translation…)

 

 

Module MainModule

    Sub Main()

        Dim c As New Customer()

        c.Name = "Jerry Dennany"

        ProcessCustomer.ProcessCustomerName(c.Name)

    End Sub

End Module

 

Class Customer

    Private _name As String

    Public Property Name() As String

        Get

            Return _name

        End Get

 

        Set(ByVal value As String)

            _name = value

        End Set

    End Property

End Class

 

Class ProcessCustomer

    Public Shared Sub ProcessCustomerName(ByRef CustomerName As String)

        ' Do something here

    End Sub

End Class

 

This time, we get no blue squiggly!  Now, there’s a .NET CLR constraint against a set taking place, so what’s going on here?

 

Well, if we look behind the scenes, here’s how the VB.NET compiler actually codes this:

 

Public Shared Sub Main()

    Dim c As Customer = New Customer

    c.Name = "Jerry Dennany"

    Dim c2 As Customer = c

    Dim tempText As String = c2.Name

    ProcessCustomer. ProcessCustomerName(tempText)

    c2.Name = tempText

End Sub

 

It makes sense, now that we look at the code generation done behind the scenes by the VB.NET compiler.  By setting a temporary variable, and then resetting the original property, VB.NET solves this issue.  Now, many C# people may be looking at this and wondering why this is a big deal.  It’s not, really, but it’s an example of how the VB.NET compiler goes that extra mile.

 

I ran into this recently when I was converting a very large VB.NET project to C#.  There were several hundred places in the code where this occurred, and this issue, along with many others, rendered the conversion very difficult to perform.  So, the next time someone tries to tell you that VB.NET and C# are the same thing, you might want to politely remind them that enough small differences make switching languages non-trivial on a large project.

This one hit my team pretty hard.

FIX: An assertion error occurs when you insert data in the same row in a table by using multiple connections to an instance of SQL Server

We had a customer with a major production issue - The SQL Server was throwing stack traces at random intervals, and the SQL connection would die.  We traced the issue to a specific stored procedure, and from there, to a specific line of T-SQL.  The problem was, the T-SQL was perfectly legal, and valid.  I searched the newsgroups, and http://support.microsoft.com, but had no luck.  So, next stop was Microsoft's Product Support Team for SQL Server.

It wasn't the dream experience I had hoped for.  I've dealt with the MSMQ PSS team on several occasions, and it's always been a pleasure.  However, there were several turn-offs when dealing with SQL Server PSS.

1.  I didn't deal with a Microsoft employee.  He was a contractor (as noted by the 'v-' prefix to the email address.  Note to MS: You give away too much business information in your email to external people).  Frankly, I don't even think that he worked directly for the Microsoft.  Every conference call I had gave me the distinct impression that he was sitting in another office, let's call it Company X.

2.  It was apparent that he didn't have a direct communications channel with the SQL Server engineers.  This is a real problem, as the issue was a SQL Server bug, not a problem with our code.  T-SQL should NEVER generate a stack trace, and yet the original approach to the issue seemed to be to analyze the T-SQL to see if we were doing something wrong.  We weren't.

3.  Troubleshooting the problem required generating two SQL Server memory dumps, which bring down the SQL Server for up to twenty minutes.  This is a major issue, as this server runs at a major hospital, and bringing it down directly impacts patient care.

4.  After generating the memory dump, PSS assured us that there was a released hotfix for the issue.  It was actually for an unrelated issue.

5.  Testing revealed that the hotfix didn't fix the issue.  We complained, and microsoft released a new hotfix. 

6.  This is the part that makes me really upset, so let me pause for a second.  

Ok, I'm ready.

If you look at the example stack trace in the KB article, you see that it is from 2001 !!!!  That means that they've known about this issue for three years!  I understand not fixing it for three years, but the support team wasn't even aware of the bug.  It still took three months for them to troubleshoot the identical issue on our systems.  That really shows me that there was a lack of communication between the PSS team and the Engineering Team.  This is really disappointing, 

I'd go on, but I'm kind of upset.  This bug has caused me much unrest, and in the end, I am certainly glad that we have a resolution.

Aaahhh!

One of my pet peeves, actually, is that sprinkled throughout the framework are many places that insist on taking a char[].  The instance method String.Split() is one such example, though I am certain that you will see many others. 

Why, oh why didn't we overload these methods to take a String?  It's not like I keep a char[] in my pocket, just waiting to use.  I've got to dust off a Char.Parse(), or some such ugly construct.

The String is one of the most natural objects in the framework.  Microsoft really got something right here, with a unified string type, instead of the mess of BSTR and LPSTR and char* and CString and wchar and TCHAR and LPCTSTR and basic_string and (breath, Jerry, breath!!)...

And, I'm not even mentioning the custom strings that people write for C++.  I think I would run out of blog space here.

So, since the String class is one of the most "natural" types in .NET, a string parameter should be the type of choice when passing charactor data.   Does anyone really have a good reason to offer a char[] param, and not a corresponding String overload?

More Posts