views:

33

answers:

2

Having a separate helper assembly containing only P/Invoke declarations for legacy 3rd party components, I wonder which of these two ways is The Better One™ if the assembly must be marked CLS compliant:

  • Use Int32 in a public P/Invoke declaration where the unmanaged declaration has unsigned int.
  • Use UInt32 in an internal P/Invoke declaration where the unmanaged declaration has unsigned int, and wrap it in a public method that takes an Int32 and converts it to UInt32 when calling the internal method.

What are the up- and downsides of these?

+1  A: 

I don't think you'd get correct behavior if you went with option 1. Int32 can only go as high as 2,147,483,647. Whereas the unsigned int goes up to 4,294,967,295. As long as you KNOW you don't need any values above 2 billion, it doesn't really matter. But to be technically correct, the public interface should expose a larger type and perform bounds checking to make sure it fits in an unsigned int and throw an exception if it doesn't. An Int64 will do (9,223,372,036,854,775,807).

colithium
+1  A: 

The P/Invoke marshaller isn't going to complain when the uint gets too big, you'll just end up with a negative int. The extra layer does allow you to use the checked keyword to generate an OverflowException. Which is fairly desirable.

Whether it is worth the hassle is a secondary question. Lots of APIs, like Win32, use unsigned as a logical constraint. Like the length of the string or the size of a block of memory, it can never be negative. In practice, such a number can never overflow. Because it isn't possible to allocate that much memory. I can't remember running once in an API where it was a slam-dunk that uint should be used. As such, I think you're fine just using a straight pinvoke declaration with ints.

Hans Passant