GOTCHA 1 Type alias size doesn t match what you re familiar with


GOTCHA #1 Type alias size doesn't match what you're familiar with

The Common Language Specification (CLS) provides rules to enable interoperation of types written in different languages. The Common Type System (CTS) enables cross-language integration, type safety, and high-performance execution of managed code. However, not all types supported in the .NET Framework are interoperable or CLS-compliant. When developing your class library, make sure the types you write and expose are CLS-compliant. Run your code through FxCop to make sure it complies with the Microsoft "Design Guidelines for Class Library Developers" (see "On the Web" in the Appendix).

As a convenience to C++, Java, and VB6 programmers, .NET languages provide aliases for the CTS data types, like int and long in C# and Integer and Long in VB.NET [Albahari02, Drayton03, Evjen04, Hamilton03, Robinson04, Thai03]. The aliases appear to match data types in those other languages, but some of the most important do not.

If you're a C++ programmer, you might assume that a long in C# corresponds to a long in C++. If you're coming from VB6, you might think that Integer and Long in VB.NET are equivalent to the Integer and Long you're used to in VB6. But in both cases, you'd be wrong.

Let's look at an example. How do I make an application beep? One possibility is to use PInvoke to call the Win32 Beep() method. PInvoke is a .NET facility that allows managed code to call unmanaged functions in DLLs. In VB6, Beep() has this declaration:

 Beep(dwFreq as Long, dwDuration as Long) as Boolean 

The Long type in VB6 is a 32-bit integer.

The underlying Win32 prototype is:

 Beep(dwFreq as DWORD, dwDuration as DWORD) as Boolean 

Now, let's use Beep() in .NET. The code to do this is shown in Example 1-1:

Example 1-1. Producing Beeps

C# (Aliases)

 using System; using System.Runtime.InteropServices; namespace InvokeBeep {     class Test     {         [DllImport("kernel32")]         public static extern bool Beep(long dwFreq,             long dwDuration);         [STAThread]         static void Main(string[] args)         {             Beep(1000, 1000);         }     } } 

VB.NET# (Aliases)

 Imports System.Runtime.InteropServices Module Module1     Public Declare Function Beep Lib "Kernel32" ( _         ByVal dwFreq As Long, ByVal dwDuration As Long) As Boolean     Sub Main()         Beep(1000, 1000)     End Sub End Module 

When you compile and run this example, it fails to produce the desired result. On my system, I don't hear any beeps. What went wrong?

While the CTS defines the data types available to all .NET languages, such as System.Int32 and System.Double, each .NET language defines its own aliases for these types. For instance, C# uses int as an alias for System.Int32 and VB.NET uses Integer. These aliases appear to correspond to the types C++ developers (in the case of C#) and VB6 developers (in the case of VB.NET) are familiar with.

Table 1-1 shows the CTS types and the size differences between C# and C++. Table 1-2 shows the CTS types and the size differences between VB.NET and VB6.

Table 1-1. Some CTS types and aliases in C#

CTS type

Size

C# alias

Type equivalent in C++

System.Int32

4 bytes

int

int or long

System.Int64

8 bytes

long

_ _int64

System.Char

2 bytes

char

WCHAR

System.Double

8 bytes

double

double


Table 1-2. Some CTS types and aliases in VB.NET

CTS type

Size

VB.NET alias

Type equivalent in VB

System.Int32

4 bytes

Integer

Long

System.Int64

8 bytes

Long

N/A

System.Char

2 bytes

Char

String * 1

System.Double

8 bytes

Double

Double


As you can see from these tables, a long in C++ is not the same size as a long in C#. Nor is a Long in VB6 the same size as a Long in VB.NET. Long in VB6 corresponds to Integer in VB.NET. In the code of Example 1-1, you were actually passing 64-bit arguments to a function that expected 32 bits due to the improper declaration of the Beep() method. The code change in Example 1-2 fixes the problem.

Technically, sending an Integer in VB.NET is not a completely accurate mapping. Beep() expects two unsigned 32-bit (DWORD) arguments. A VB.NET Integer is a signed 32-bit integer. There is no VB.NET alias for System.UInt32 (which is not CLS-compliant). You may use System.UInt32 as the parameter type in the Beep method.

You can take a trial-and-error approach to figuring out the PInvoke signature in C#/ VB.NET. Or you can quickly look up the signature for most Win32 and other APIs at http://www.pinvoke.net.

Example 1-2. Proper declaration for the Beep method

C# (Aliases)

         [DllImport("kernel32")]         public static extern bool Beep(uint dwFreq,             uint dwDuration); 

VB.NET (Aliases)

     Public Declare Function Beep Lib "Kernel32" ( _         ByVal dwFreq As Integer, ByVal dwDuration As Integer) _ As Boolean 

IN A NUTSHELL

Be mindful of the sizes of the aliases used in .NET languages. If in doubt, use the fully qualified name from the CTS, as in System.Integer. For PInvoke signatures, look up the correct type mapping at http://www.pinvoke.net.

SEE ALSO

Gotcha #2, "struct and class differ in behavior."



    .NET Gotachas
    .NET Gotachas
    ISBN: N/A
    EAN: N/A
    Year: 2005
    Pages: 126

    flylib.com © 2008-2017.
    If you may any questions please contact us: flylib@qtcs.net