views:

375

answers:

5

I am writing a library in VB.NET in which I have added, among others, a class originally written in C# but converted into VB.NET. I don't know much about C# so therefore I have used online C# to VB.NET-converters. Now I am stuck with some code which I believe the online-converter was not able to "translate" properly.

When running the code I get the following error:

System.IndexOutOfRangeException was unhandled
  Message="IndexOutOfRangeException"
  StackTrace:
    at System.String.get_Chars()
.........

I really don't understand the reason for this error. I believe this error might be due either: - to the fact that C# is able to automatically convert an integer variable into a string (while VB.NET needs the "toString-method") - or due to the fact C# is using an incremental operator which is not supported by VB.NET.

Here is the original code-snippet in C# where "m_primaryKey" is a StringBuilder-object:

private void addMetaphoneCharacter(String primaryCharacter, String alternateCharacter)
        {
            //Is the primary character valid?
            if (primaryCharacter.Length > 0)
            {
                int idx = 0;
                while (idx < primaryCharacter.Length)
                {
                    m_primaryKey.Length++;
                    m_primaryKey[m_primaryKeyLength++] = primaryCharacter[idx++];
                }
            }
            //other code deleted

This original code works when using a class-library created in C#.

Here is the converted code in VB.NET which gives me the error mentioned earlier:

Private Sub addMetaphoneCharacter(ByVal primaryCharacter As String, ByVal alternateCharacter As String)
            'Is the primary character valid? 
            If primaryCharacter.Length > 0 Then
                Dim idx As Integer = 0
                While idx < primaryCharacter.Length
                    m_primaryKey.Length += 1
                    m_primaryKey(System.Math.Max(System.Threading.Interlocked.Increment(m_primaryKeyLength), _
                        m_primaryKeyLength - 1)) = primaryCharacter _
                        (System.Math.Max(System.Threading.Interlocked.Increment(idx), idx - 1))
                End While
            End If 
           'other code deleted

The original code may be found here.

I should say that the code in the class is quite advanced for me (I'm a hobby programmer but learning every day) so maybe I don't see obvious things but this is the reason why I am asking you.

Can you please give me any hints to sort out this problem?

Thank you.

EDIT: Here is the complete sub in C#:

/**
         * Appends a metaphone character to the primary, and a possibly different alternate,
         * metaphone keys for the word.
         * 
         * @param primaryCharacter
         *               Primary character to append to primary key, and, if no alternate char is present,
         *               the alternate key as well
         * @param alternateCharacter
         *               Alternate character to append to alternate key.  May be null or a zero-length string,
         *               in which case the primary character will be appended to the alternate key instead
         */
        private void addMetaphoneCharacter(String primaryCharacter, String alternateCharacter)
        {
            //Is the primary character valid?
            if (primaryCharacter.Length > 0)
            {
                int idx = 0;
                while (idx < primaryCharacter.Length)
                {
                    m_primaryKey.Length++;
                    m_primaryKey[m_primaryKeyLength++] = primaryCharacter[idx++];
                }
            }

            //Is the alternate character valid?
            if (alternateCharacter != null)
            {
                //Alternate character was provided.  If it is not zero-length, append it, else
                //append the primary string as long as it wasn't zero length and isn't a space character
                if (alternateCharacter.Length > 0)
                {
                    m_hasAlternate = true;
                    if (alternateCharacter[0] != ' ')
                    {
                        int idx = 0;
                        while (idx < alternateCharacter.Length)
                        {
                            m_alternateKey.Length++;
                            m_alternateKey[m_alternateKeyLength++] = alternateCharacter[idx++];
                        }
                    }
                }
                else
                {
                    //No, but if the primary character is valid, add that instead
                    if (primaryCharacter.Length > 0 && (primaryCharacter[0] != ' '))
                    {
                        int idx = 0;
                        while (idx < primaryCharacter.Length)
                        {
                            m_alternateKey.Length++;
                            m_alternateKey[m_alternateKeyLength++] = primaryCharacter[idx++];
                        }
                    }
                }
            }
            else if (primaryCharacter.Length > 0)
            {
                //Else, no alternate character was passed, but a primary was, so append the primary character to the alternate key
                int idx = 0;
                while (idx < primaryCharacter.Length)
                {
                    m_alternateKey.Length++;
                    m_alternateKey[m_alternateKeyLength++] = primaryCharacter[idx++];
                }
            }
        }
+1  A: 

Index out of bound means that you are trying to access outside of the size of the array. This is usually caused by a "over by one" issue.

Looking at the code, the VB conversion is rather odd, and is doing things that the C# version does not, such as removing one from the indexer.

You are saying an automated tool did this?

By the way, you can include C# classes and assemblies in a VB application without any trouble, so why are you converting this?

FlySwat
I'm writing a class-library (not an app) in VB.NET. I need this code (which is part of a class I found in C# - DoubleMetaPhone - a phonetic algorithm). I want everything included in my library but if I can include pure C#-code in my VB-net library without converting it, I'd love to know how.
moster67
Compile the C# classes into a DLL and reference that DLL in your VB DLL.
FlySwat
But does that means when distributing my DLL, that I need to include the other DLL written in C#?
moster67
+2  A: 

The arguments to the second line of the while loop are quite different in the VB.NET version. The Interlocked.Increment calls will be returning the incremented index, whereas the C# post-increment operator returns the original value (before the increment).

That second line would probably be better replaced with something like:

m_primaryKey(m_primaryKeyLength) = primaryCharacter(idx)
m_primaryKeyLength = m_primaryKeyLength + 1
idx = idx + 1

i.e. incrementing the values only after doing the indexing/assignment, as per the C# original.

itowlson
that was the trick - many thanks!
moster67
+1  A: 

I might be missing something, but I fail to see the relevance of why the convertor has started using System.Threading.Interlocked....

My manual conversion would look something like this:

Private Sub addMetaphoneCharacter(ByVal primaryCharacter As String, ByVal alternateCharacter As String)
            'Is the primary character valid? 
            If primaryCharacter.Length > 0 Then
                Dim idx As Integer = 0
                While idx < primaryCharacter.Length
                    m_primaryKey.Length += 1
                    m_primaryKey(m_primaryKeyLength) = primaryCharacter(idx)
                    m_primaryKeyLength += 1
                    idx += 1

                End While
            End If 
           'other code deleted
Martin Clarke
I have no idea why the converter used System.Threading.Interlocked.. In any case, your answer is the same as itowlson's one but I can only assign one accepted answer. Sorry for that but many thanks to you as well.
moster67
+1 well deserved in any case
moster67
A: 

Changing the Math.Max to Math.Min should fix the issue, however for clarity I would change as itowlson said, and move the increments to after their use.

Daniel
I will try out your suggestion as well. Thanks.
moster67
A: 

The two lines of code in your while loop do the following in C#: - increment m_primaryKey.Length by one - increment m_primaryKeyLength by one (are you sure you aren't missing a dot here?) - increment idx by one - assign the value of primaryCharacter[idx] to m_primaryKey[m_primaryKeyLength]

So in VB code...

m_primaryKey.Length += 1
m_primaryKeyLength += 1
idx += 1

m_primaryKey(m_primaryKeyLength) = primaryCharacter (idx)

I can't tell from this code snippet, but it smells like m_primaryKeyLength and m_primaryKey.Length are redundant. If this is the case, simplify your code by replacing "m_primaryKeyLength" with "m_primaryKey.Length".

JoshL
I may be wrong here, but I think the increments to m_primaryKeyLength and idx need to come after the assignment, not before it -- the C# is using a post-increment rather than a pre-increment.
itowlson