Best vb.net questions in August 2010

How do I tune up my C# Skills, when I have spent the last decade coding in VB?

11 votes

I started my career coding in C/C++ on a vax system, but got into a few contracts where it was all VB and then became a specialist in VB, then to VB.net. Now I am aspiring to work for Microsoft and it seems that every job they post is in C/C++/C# and I can barely read C# code, it looks like the most convoluted mess to me and the inline syntax almost hurts my feelings.

I am looking for positive, non-flaming, helpful suggestions on how to pick up C# skills again. Books..Labs..etc? I have been coding simple projects using Silverlight and C# to try and work it out but it is extremely frustrating since there are very few examples that I can find that illustrate what each code set looks like. I've Googled but have yet to find anything helpful other than channel9 labs and working through some of the example code/projects from mix10.

I am not looking for a shortcut, but a good solid skills understanding. I swear it is easier to translate English to Latin than VB to C#.

I personally would start by converting a VB.NET project into C#, having done VB.NET it wouldn't be difficult once you got started as they both use the same underlying CLR.

Doing it this way step by step, looking up how to convert each bit you don't understand, you'll soon end up teaching yourself C# based on you're knowledge of VB.NET and you'll see they're really not that much different!

I find them very similar now I know them both, they just have a habit of doing things 'slightly' differently.

Also, have a look at this wiki page for a summary comparison of VB.NET and C#, and check out the examples at the bottom to see some basic syntax comparisons that will give you a starting point for converting VB.NET into C#.

TryCast fails where DirectCast works (.NET 4.0)

9 votes

I find this behavior of TryCast in .NET 4.0 / VS 2010 rather confusing.

In my understanding TryCast works like DirectCast, but will return Nothing instead of throwing an exception if a conversion is not possible.

VS 2010 / .NET 4

?TryCast(CType(1, Object), String)
Nothing
?DirectCast(CType(1, Object), String)
"1"

VS 2008 / .NET 3.5

?TryCast(CType(1, Object), String)
Nothing
?DirectCast(CType(1, Object), String)
Cannot convert to 'String'.

The .NET 3.5 results are consistent with what I believe TryCast does... .NET 4 however is not.

Can someone please point me in the best direction to securely cast an object to String in .NET 4?

Based on your code samples starting with the ? I'm guessing you're using the immediate window to perform your test correct? The problem with this approach is that the immediate window is an interpretation instead of an actual evaluation. This leaves it susceptible to subtle corner case bugs and this is indeed one of them.

If you take your sample code and add it to a simple VB.Net console application you'll find that the 2010 behavior is identical to the 2008 behavior (throws an exception).

EDIT

So why did this regression happen? In 2010 I completely rewrote the VB EE debugging engine (expression evaluator). The older code base I inherited was simply too costly to maintain anymore. To the point that adding new features to the engine was more expensive that rewriting it from scratch with a better architecture that included the new features.

As said before debugging evaluations is an interpretation more than an execution of code. It forces the duplication of some algorithms between the EE and CLR / Compiler. One of the areas where duplication occurs is in the casting logic. There is no way to ask the CLR debugger to cast a debug time object, it's the responsibility of the EE to determine if the language specified cast is indeed valid.

The old EE casting logic had numerous bugs (especially in the area of generics and arrays). The newer infrastructure conforms very closely to the CLR guidelines. However you'll never have 100% parity because it would disallow very useful expressions in the EE (I may write a blog post on this in the future). But for most cases the behavior holds.

In this particular instance I added a subtle bug which allows for a DirectCast of a value which is typed to Object to use VB's Runtime Conversion operators vs. the specified behavior which only allows for CLR conversions. Hence this conversion succeeds where it should fail.

Need .NET code to execute only when in debug configuration

8 votes

I have some code that access an API out on the web. One of the API's parameters allows me to let them know that I am testing.

I would like to only set this parameter in my code when I am testing. Currently, I just comment the code out when I do a release build.

Is there an automatic way of doing this based on the build configuration?

yes, wrap the code in

#if DEBUG
// do debug only stuff 
#else
// do non DEBUG stuff
#endif

Google for "C# compilation symbols"

Visual Studio automatically defines DEBUG when you are in the debug configuration. You can define any symbols you want (look at your project's properties, the build tab). Beware that abusing preprocessor directives is a bad idea, it can lead to code that is very difficult to read/maintain.

What is IIF in C#?

8 votes

Possible Duplicate:
iif equivalent in c#

I have several lines of code using IIF in VB.

I am trying to convert this code to C#. HEre's an example where I need help.

intCurrency = IIf(or.Fields("Currency").Value = "USD", 100, 0)

How do I change the above line of code to CSharp? Is there a short-circuit evaluation operator in C#?

It is close to the C# ternary / conditional operator as several people have suggested but it is not an exact replacement. The C# ternary operator does short circuit evaluation meaning that only the side effect of the evaluated clause occurs. In VB.Net the Iif function does not implement short circuiting and will evaluate both side effects.

Additionally the Iif function in VB.Net is weakly typed. It accepts and returns values typed as Object. The C# ternary operator is strongly typed.

The closest equivalent you can write is the following. Putting the values into the arguments forces the evaluation of their side effects.

public static object Iif(bool cond, object left, object right) {
  return cond ? left : right;
}

Or slightly more usable

public static T Iif<T>(bool cond, T left, T right) {
  return cond ? left : right;
}

Is there a way to change the order of constructors listed in IntelliSense in Visual Studio?

7 votes

I have defined a class with multiple constructors so that the underlying interfaces are immutable once the object is instantiated. I would like one of the constructors to be the "default" constructor for when a user types the following in Visual Studio:

var obj = new MyClass(

Dim obj As New MyClass(

Currently when I go to instantiate the object, the constructors aren't listed (in Visual Studio IntelliSense) in the order I declared them in my class. Is there a way to mark up my constructors so that their methods appear in a particular order during instantiation in Visual Studio IntelliSense?

There isn't a way to control the ordering within Visual Studio's Intellisense. If you do have multiple constructors (or methods), your only real control in terms of intellisense is to use EditorBrowsable with the appropriate EditorBrowsableState. This allows you to hide a contructor (or method) in intellisense, or only have it displayed in "advanced" mode, but does not allow you to reorder them.

However, in this situation, if you're targetting .NET 4, I'd recommend considering using a single constructor, and taking advantage of named and optional arguments.

Is there any limit on number of classes that a namespace can have in .net ?

7 votes

Is there any limit on number of classes that a namespace can have in .net ? Further what is the recommended number of classes that there should be in a namespace?

I tried it out: I just built an assembly containing 1,000,000 types without any problem. However at 5,000,000 the C# compiler ran out of memory :-).

Should development of a new application be in C# or VB.NET?

7 votes

Should development of a new application be in C# or VB.NET?

How can we decide which language to use when there is no customer or resource requirements?

Is it dependent on the flavor which we like the most?

I think the first thing you should look at is which you are most comfortable with. What competence does your company have? As has been mentioned, there is a lot of supporting documentation around C# and a large community has sprung up around it. If you have the time and it is acceptable though, it might be a good idea to develop you skills in the language you are least proficient in, but I doubt your client would like that. :)

Issues with checking the equality of two doubles in .NET -- what's wrong with this method?

6 votes

So I'm just going to dive into this issue... I've got a heavily used web application that, for the first time in 2 years, failed doing an equality check on two doubles using the equality function a colleague said he'd also been using for years.

The goal of the function I'm about to paste in here is to compare two double values to 4 digits of precision and return the comparison results. For the sake of illustration, my values are:

Dim double1 As Double = 0.14625000000000002 ' The result of a calculation
Dim double2 As Double = 0.14625 ' A value that was looked up in a DB

If I pass them into this function:

Public Shared Function AreEqual(ByVal double1 As Double, ByVal double2 As Double) As Boolean

    Return (CType(double1 * 10000, Long) = CType(double2 * 10000, Long))

End Function

the comparison fails. After the multiplication and cast to Long, the comparison ends up being:

Return 1463 = 1462

I'm kind of answering my own question here, but I can see that double1 is within the precision of a double (17 digits) and the cast is working correctly.

My first real question is: If I change the line above to the following, why does it work correctly (returns True)?

Return (CType(CType(double1, Decimal) * 10000, Long) = _
    CType(CType(double2, Decimal) * 10000, Long))

Doesn't Decimal have even more precision, thus the cast to Long should still be 1463, and the comparison return False? I think I'm having a brain fart on this stuff...

Secondly, if one were to change this function to make the comparison I'm looking for more accurate or less error prone, would you recommend changing it to something much simpler? For example:

Return (Math.Abs(double1 - double2) < 0.0001)

Would I be crazy to try something like:

Return (double1.ToString("N5").Equals(double2.ToString("N5")))

(I would never do the above, I'm just curious about your reactions. It would be horribly inefficient in my application.)

Anyway, if someone could shed some light on the difference I'm seeing between casting Doubles and Decimals to Long, that would be great.

Thanks!

Relying on a cast in this situation is error prone, as you have discovered - depending upon the rules used when casting, you may not get the number you expect.

I would strongly advise you to write the comparison code without a cast. Your Math.Abs line is perfectly fine.

Regarding your first question:

My first real question is: If I change the line above to the following, why does it work correctly (returns True)?

The reason is that the cast from Double to Decimal is losing precision, resulting in a comparison of 0.1425 to 0.1425.

Should I use (otherwise optimal) class names that conflict with the .NET BCL's names?

6 votes

This situation probably is not entirely uncommon to some of you: you have some functionality to put in a class but the perfect name (*) for that class is taken by one of the classes in the System namespace or other namespace/class that's not yours but you're using/importing.

(*) By perfect I mean small, concise and clear names.

For instance I have an Utils class that has a Diagnostics (mostly debug utils) class and a Drawing class. I could:

  1. have a DrawingUtils class and a DiagnosticsUtils class, but that just smells like bad structure.
  2. pick a thesaurus and be done with an worse, longer or awkward name that's casually still not taken.
  3. Write class names in my native language instead of English.
  4. Ask the smart guys at StackOverflow.

I think options 1-3 aren't promising :(

EDIT:

Since my chosen answer doesn't address the problem definitively (neither I do), what I'd recommend for people facing the same situation is to ask yourselves: Will you frequently use the conflicting BCL class/namespace? If no, then let your name conflict (as I did with Diagnostics). If yes, add a word that limits the possibilities of your class/namespace.

In practice, this means:
"Drawing": Something that draws.
"MyCustomControlDrawing": Something that draws only on MyCustomControl. e.g.: "WidgetDrawing".

EDIT2:

Another solution to take a look next time: Extension Methods (courtesy of Lawnmower).

Use namespaces to disambiguate your classes from the classes in other namespaces. Either use fully qualified names or a using statement that tells the compile what you need:

using Type = MyReallyCoolCustomReflector.Type;

Now if you want to still use the Type class from the System namespace:

System.Type sysType = anObject.GetType();

Generally I try to avoid name duplicates but this doesn't always work out that way. I also like simple, readable and maintainable code. So as often it is a trade-off decision.

How do you implement the equivalent of SQL IN() using .net

5 votes

In .net (c# or vb) expressions, how would you implement SQL's handy IN() functionality?

i.e. value in (1, 2, 4, 7)

rather than:

value = 1 or value = 2 or value = 4 or value = 7

There are obviously many ways, I'm looking for the most clean and simple!

using System;
using System.Linq;

static class SqlStyleExtensions
{
    public static bool In(this string me, params string[] set)
    {
       return set.Contains(me);
    }
}

Usage:

if (Variable.In("AC", "BC", "EA"))
{

} 

VB.Net WinForms Form OnPaint() Transparency Refresh

5 votes

Long story short, I'm trying to write some toast-style popup notifications (similar to Growl) which should appear next to the system tray and stack as appropriate.

I can handle the instantiation/location/etc... but I want to add a capability for non-rectangular toasts. I'd also like to have Alpha transparency so a semi-transparent background PNG on the toast form would blend with the desktop or windows behind it.

So... To get the obvious out of the way:

Form.TransparencyKey is not sufficient for my needs as it's an all-or nothing transparency effect I want to get 50/50 foreground/background in some places, 0/100 in others, 100/0 in yet others etc.

My initial approach is to override the OnBackgroundPaint() method, comment out the call to MyBase.OnBackgroundPaint and use the graphics object in the eventargs to draw exactly what I want to a form.

This seems to work to start with - at the moment, I'm just drawing some rectangle for testing purposes so a PNG may present new difficulties but I haven't got there yet.

What I haven't been able to accomplish is updating the graphic - The first time the form is rendered, it shows perfectly as I'd expect (no border, just some rectangles floating on a desktop). If I move the windows behind the transparent window, the transparent window doesn't update/re-paint

I believe that I need to be calling Me.Invalidate() to force a re-draw but am unsure when I should make the call - How do I know a window behind me has changed its' contents?

Am I taking the wrong approach?

Many thanks

Edit: I tried putting a Me.Invalidate() inside a timer just to test how the redraw happens - it seems that it does trigger a re-draw but the re-draw opccurs OVER the existing form background - ie an area that was originally 50% opaque is now 75% opaque (50% + 50% of what was there before)

So, after a couple of Invalidate()s, my form is showing as a black box - I need to clear the background of the form before re-drawing but Graphics.Clear(Color) seems to simply do a fill with the specified color - and obviously for the purposes of this question, Colors.Transparent doesn't really mean transparent - It seems to be a trick used when rendering the window to "show contents of control beneath this" which just doesn't work when we're dealing with the form itself

In case anyone wants to replicate easily, the code for my form is below:

Imports System.Drawing
Public Class TransparentForm

    Private Timer As Timers.Timer

    Private Sub TransparentForm_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Timer = New Timers.Timer
        AddHandler Timer.Elapsed, AddressOf Timer_Tick
        Timer.Interval = 100
        Timer.Start()
    End Sub

    Protected Overrides Sub OnPaintBackground(ByVal e As System.Windows.Forms.PaintEventArgs)
        ''MyBase.OnPaintBackground(e)
        Console.WriteLine("BackgroundPainted")
        For x = 0 To 9
            e.Graphics.FillRectangle(
                New SolidBrush(Color.FromArgb(CInt(x / 10 * 255), 127, 127, 127)),
                CInt(x * Me.Width / 10),
                0,
                CInt(Me.Width / 10),
                Me.Height
            )
        Next
    End Sub

    Sub Timer_Tick(ByVal sender As Object, ByVal e As EventArgs)
        Me.Invalidate()
    End Sub

    Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs)
        MyBase.OnPaint(e)
        Console.WriteLine("Painted")
    End Sub

    Protected Overrides Sub OnInvalidated(ByVal e As System.Windows.Forms.InvalidateEventArgs)
        MyBase.OnInvalidated(e)
        Console.WriteLine("Invalidated")
    End Sub

End Class

There is one CodeProject article that shows how to use a png as the form's "skin". Obviously, this supports partial transparency instead of the 50/50 approach offered by Form.TransparencyKey.

This is the link to the codeproject article. I'm trying to upload the project in VB and will update this answer as soon as it is done.


EDIT

Here's the link to the VB.NET version of the CodeProject article I cited above.
http://www20.zippyshare.com/v/86701716/file.html

I'll try to review your code and see what can be done to help your situation.

Codedom and string handling

5 votes

I've researched on this but couldn't find anything solid and wanted to see if someone can point me in the right direction. I'm trying to see if Codedom can handle strings and concantination between different languages, without me setting up conditional strings per language.

For example, I need to generate the following exactly as shown below in both C# and VB.NET via Codedom:

C#

errorMsg = errorMsg.Replace('"', '\'').Replace("\r\n", @"\n");
System.Windows.Browser.HtmlPage.Window.Eval("throw new Error(\"Unhandled Error in Silverlight Application " + errorMsg + "\");");  

VB.NET

errorMsg = errorMsg.Replace(""""c, "'"c).Replace(ChrW(13) & ChrW(10), "\n")
System.Windows.Browser.HtmlPage.Window.Eval("throw new Error(""Unhandled Error in Silverlight Application " + errorMsg + """);")

The CodeMethodInvokeExpression for errorMsg.Replace and System.Windows.Browser.HtmlPage.Window.Eval is simple enough, it's the string inside them that I can't figure out if Codedom can automatically handle.

Unfortunately code primitives, when combined, don’t always produce desired results because the provider will take certain liberties to interpret intent. The way around this is to use a CodeSnippetExpression.

Here’s code (VB.NET & C#) that works to produce the Eval statements that you listed in your question. Feel free to use whichever works best for you:

VB.NET Version

Imports System.CodeDom
Imports System.CodeDom.Compiler
Imports System.Reflection
Imports System.Text
Imports System.IO
Imports Microsoft.CSharp

Public Class PrintEvalStatement
    Public provider As CodeDomProvider

    Sub New()
        Dim left As New CodePrimitiveExpression("throw new Error(""Unhandled Error in Silverlight Application ")
        Dim middle As New CodeVariableReferenceExpression("errorMsg")
        Dim right As New CodePrimitiveExpression(""");")

        Dim targetObject = New CodeTypeReferenceExpression("System.Windows.Browser.HtmlPage.Window")
        Dim methodName = "Eval"

        provider = New VBCodeProvider()
        Dim vbStatement As String = ConcatStatement(left, middle, right, targetObject, methodName)

        provider = New CSharpCodeProvider()
        Dim csStatement As String = ConcatStatement(left, middle, right, targetObject, methodName)

        Console.WriteLine(vbStatement)
        Console.WriteLine(csStatement)
        Console.ReadLine()
    End Sub

    Private Function ConcatStatement(ByVal left As CodePrimitiveExpression,
                                     ByVal middle As CodeVariableReferenceExpression,
                                     ByVal right As CodePrimitiveExpression,
                                     ByVal targetObject As CodeTypeReferenceExpression,
                                     ByVal methodName As String) As String
        Dim evalMessage As New CodeExpression
        evalMessage = ConcatString(left, middle, right)

        Dim eval As New CodeMethodInvokeExpression(targetObject, methodName, evalMessage)
        Dim evalStatement As New CodeExpressionStatement(eval)
        Dim sw As StringWriter = New StringWriter()

        Using tx As TextWriter = New StringWriter()
            provider.GenerateCodeFromStatement(evalStatement, tx, New CodeGeneratorOptions())
            Return tx.ToString()
        End Using
    End Function
    Private Function ConcatString(ByVal left As CodeExpression,
                                  ByVal middle As CodeExpression,
                                  ByVal right As CodeExpression) As CodeExpression
        Return New CodeSnippetExpression(CodeToString(left) + " + " + CodeToString(middle) + " + " + CodeToString(right))
    End Function
    Private Function CodeToString(ByVal expr As CodeExpression) As String
        Using tx As TextWriter = New StringWriter()
            provider.GenerateCodeFromExpression(expr, tx, New CodeGeneratorOptions())
            Return tx.ToString()
        End Using
    End Function


End Class

C# Version

using System.CodeDom;
using System.CodeDom.Compiler;
using System.Reflection;
using System.Text;
using System.IO;
using Microsoft.CSharp;
using Microsoft.VisualBasic;

namespace CodeDom
{
    class Program
    {       
        static CodeDomProvider provider;

        static void Main(string[] args)
        {
            Program shell = new Program();
            provider = new VBCodeProvider();
            CodePrimitiveExpression left = new CodePrimitiveExpression("throw new Error(\"Unhandled Error in Silverlight Application\")");
            CodeVariableReferenceExpression middle = new CodeVariableReferenceExpression("errorMsg");
            CodePrimitiveExpression right = new CodePrimitiveExpression("\");");

            CodeTypeReferenceExpression targetObject = new CodeTypeReferenceExpression("System.Windows.Browser.HtmlPage.Window");
            string methodName = "Eval";

            string vbStatement =  shell.ConcatStatement(left, middle, right, targetObject, methodName);

            provider = new CSharpCodeProvider();

            string csStatement = shell.ConcatStatement(left, middle, right, targetObject, methodName);

            Console.WriteLine(vbStatement);
            Console.WriteLine(csStatement);
            Console.ReadLine();

        }

        public string ConcatStatement(CodePrimitiveExpression left, CodeVariableReferenceExpression middle, CodePrimitiveExpression right, CodeTypeReferenceExpression targetObject, string methodName)
        {
            CodeExpression evalMessage = new CodeExpression();
            evalMessage = ConcatString(left, middle, right);

            CodeMethodInvokeExpression eval = new CodeMethodInvokeExpression(targetObject, methodName, evalMessage);
            CodeExpressionStatement evalStatement = new CodeExpressionStatement(eval);
            using (TextWriter tx = new StringWriter())
            {
                provider.GenerateCodeFromStatement(evalStatement, tx, new CodeGeneratorOptions());
                return tx.ToString();
            }
        }

        private CodeExpression ConcatString(CodeExpression left, CodeExpression middle, CodeExpression right) {
            return new CodeSnippetExpression(CodeToString(left) + " + " + CodeToString(middle) + " + " + CodeToString(right));
        }

        private string CodeToString(CodeExpression expr) {
            using (TextWriter tx = new StringWriter()) {
                provider.GenerateCodeFromExpression(expr,tx, new CodeGeneratorOptions());
                return tx.ToString();
            }
        }
    }
}

Can my users inject my dynamic sql?

5 votes

I'm a desktop developer writing for internal users, so I'm not worried about malicious hackers, but I would like to know if there's anything they could enter when updating a value that would execute sql on the server.

The business defines their content schema and I have a CRUD application for them that doesn't have to be changed when their schema changes because the validation details are table-driven and the updates are with dynamic SQL. I have to support single quotes in their data entry, so when they enter them, I double them before the SQL is executed on the server. From what I've read, however, this shouldn't be enough to stop an injection.

So my question is, what text could they enter in a free-form text field that could change something on the server instead of being stored as a literal value?

Basically, I'm building an SQL statement at runtime that follows the pattern:

update table set field = value where pkField = pkVal

with this VB.NET code:

Friend Function updateVal(ByVal newVal As String) As Integer
    Dim params As Collection
    Dim SQL As String
    Dim ret As Integer

    SQL = _updateSQL(newVal)
    params = New Collection
    params.Add(SQLClientAccess.instance.sqlParam("@SQL", DbType.String, 0, SQL))
    Try
        ret = SQLClientAccess.instance.execSP("usp_execSQL", params)
    Catch ex As Exception
        Throw New Exception(ex.Message)
    End Try
    Return ret
End Function

Private Function _updateSQL(ByVal newVal As String) As String
    Dim SQL As String
    Dim useDelimiter As Boolean = (_formatType = DisplaySet.formatTypes.text)
    Dim position As Integer = InStr(newVal, "'")
    Do Until position = 0
        newVal = Left(newVal, position) + Mid(newVal, position)       ' double embedded single quotes '
        position = InStr(position + 2, newVal, "'")
    Loop
    If _formatType = DisplaySet.formatTypes.memo Then
        SQL = "declare @ptrval binary(16)"
        SQL = SQL & " select @ptrval = textptr(" & _fieldName & ")"
        SQL = SQL & " from " & _updateTableName & _PKWhereClauses
        SQL = SQL & " updatetext " & _updateTableName & "." & _fieldName & " @ptrval 0 null '" & newVal & "'"
    Else
        SQL = "Update " & _updateTableName & " set " & _fieldName & " = "
        If useDelimiter Then
            SQL = SQL & "'"
        End If
        SQL = SQL & newVal
        If useDelimiter Then
            SQL = SQL & "'"
        End If
        SQL = SQL & _PKWhereClauses
    End If
    Return SQL
End Function

when I update a text field to the value

Redmond'; drop table OrdersTable--

it generates:

Update caseFile set notes = 'Redmond''; drop table OrdersTable--' where guardianshipID = '001168-3'

and updates the value to the literal value they entered.

What else could they enter that would inject SQL?

Again, I'm not worried that someone wants to hack the server at their job, but would like to know how if they could accidentally paste text from somewhere else and break something.

Thanks.

Assuming you escape string literals (which from what you said you are doing), you should be safe. The only other thing I can think of is if you use a unicode-based character set to communicate with the database, make sure the strings you send are valid in that encoding.

Differences between 32 and 64Bit .NET (4) applications

4 votes

what are the differences between 32 and 64Bit .NET (4) applications? Often 32Bit applications have problems running on 64bit machines and conversely. I know I can declare an integer as int32 and int64(certainly int64 on 32Bit systems make problems). Are there other differences between programming an 32 OR 64Bit or a both 32 AND 64Bit compatible application?

Thanks

Some differences:

  1. 32-bit and 64-bit applications can only load DLLs of the same bitness. This can be an issue for managed projects if your platform target is "Any CPU" and you reference or P/Invoke 32-bit native DLLs. The issue arises when your "Any CPU" program runs on a 64-bit machine, since your application runs as a 64-bit process. When it tries to load the 32-bit native DLL dependency, it will throw an exception (BadImageFormatException) and likely crash.

  2. There are also filesystem and registry issues. A WOW64 process that tries to read from C:\Program Files will end up getting redirected to C:\Program Files (x86) unless it first disables Windows filesystem redirection (see Wow64DisableWow64FsRedirection). For versions of Windows before Windows 7, there were also registry reflection issues that were similar to the filesystem redirection issues mentioned above. This MSDN article explains it well.

  3. Platform-specific types like IntPtr will have different sizes. This could be an issue in code that assumes a fixed size (serialization, marshaling).

  4. There are separate physical directories for the 32- and 64-bit files in the GAC. For my system, they are at C:\Windows\Microsoft.NET\assembly\GAC_32 and C:\Windows\Microsoft.NET\assembly\GAC_64.

  5. The virtual address space size of 32- and 64-bit applications is different. For 32-bit apps, the size is either 2GB (default) or 3GB (with 4GT enabled). For 64-bit apps, the size is 8TB. The 32-bit address space can be a limitation for very large applications.

  6. A little more obscure, but a lot of interprocess Win32 calls won't work between a 32- and 64-bit process. For example, a 32-bit process can fail when trying to call ReadProcessMemory on a 64-bit process. The same goes for WriteProcessMemory, EnumProcessModules, and a lot of similar methods. This can be seen in C# applications if you try to enumerate the modules of a 64-bit app from a 32-bit app using the System.Diagnostics.Process.Modules API.

Creating a comparable Dictionary Key

4 votes

I want to use a Dictionary(Of Key, Value), and the Key is not a base type, but a class like:

Public Class MyKey

    Sub New(ByVal packet As String, ByVal sent As Boolean)
        Me.packet = packet.ToUpper.Trim
        Me.sent = sent
    End Sub

    Private packet As String
    Private sent As Boolean
End Class

Now to have the Dictionary work and find the keys, I have to implement the System.IEquatable interface in the Key class (or use a different constructor, but that's another story):

Public Class MyKey
    Implements System.IEquatable(Of MyKey)


    Sub New(ByVal packet As String, ByVal sent As Boolean)
        Me.packet = packet.ToUpper.Trim
        Me.sent = sent
    End Sub

    Public Overloads Function Equals(ByVal other As MyKey) As Boolean Implements IEquatable(Of MyKey).Equals
        Return other.sent = Me.sent AndAlso other.packet = Me.packet
    End Function


    Private packet As String
    Private sent As Boolean
End Class

But to have consistent results I have also to implement Object.Equals and Object.GetHashCode:

Public Class MyKey
    Implements System.IEquatable(Of MyKey)


    Sub New(ByVal packet As String, ByVal sent As Boolean)
        Me.packet = packet.ToUpper.Trim
        Me.sent = sent
    End Sub

    Public Overloads Function Equals(ByVal other As ChiavePietanza) As Boolean Implements IEquatable(Of MyKey).Equals
        Return other.sent = Me.sent AndAlso other.packet = Me.packet
    End Function

    Overrides Function Equals(ByVal o As Object) As Boolean
        Dim cast As MyKey = DirectCast(o, MyKey)
        Return Equals(cast)
    End Function

    Public Overrides Function GetHashCode() As Integer
        Return packet.GetHashCode Or sent.GetHashCode
    End Function


    Private packet As String
    Private sent As Boolean
End Class

The question is: is that GetHashCode implementation correct? How should I implement it, to return a hashcode that kind of merges the string and the boolean hash codes?

Your GetHashCode function is correct and conforms to the known rules of hash code implementations. In particular

  • It is the same for value for equivalent instances of MyKey
  • It does not change with changes to MyKey

The one way it could be made better though is to make both packet and sent be ReadOnly fields. Right now it is implied that they are ReadOnly because they are used in a GetHashCode function. However a future developer might overlook that, mutate the values and break the contract needed for GetHashCode. Having them explicitly ReadOnly prevents accidental breaks.

Another minor note. While it's a good idea to implement IEquatable(Of T) for Dictionary keys, it is not a requirement. All that is needed is to override the Equals and GetHashCode method in order to have a key properly function in a Dictionary.