GOTCHA #1 Размеры типов псевдонимов могут отличаться
Это перевод "GOTCHA #1 Type alias size doesn't match what you're familiar with" из книги ".NET Gotchas".
Спецификация Common Language Specification (CLS) описывает правила для того, чтобы типы, написанные на разных языках, были совместимыми. Common Type System (CTS) предоставляет кросс-языковую интеграцию, безопасность типов и высокопроизводительное выполнение управляемого кода. Однако, не все типы, которые поддерживаются в .NET Framework, являются CLS-совместимыми. При разработке библиотеки классов убедитесь, что все типы, которые вы используете, являются CLS-совместимыми. Вы можете проверить свой код с помощью инструмента FxCop, чтобы убедиться, что он соответствует "Design Guidelines for Class Library Developers".
Для удобства C++, Java и VB6 программистов, семейство языков .NET содержат псевдонимы (алиасы) для CTS-типов, такие как int и long в C # и Integer и Long в VB.NET.
Если вы C++ программист, вы можете предложить, что long в C# соответствует long в C++. Если Вы пришли из мира VB6, то можете подумать, что Integer и Long в VB.NET эквивалентны Integer и Long в VB6. Но в обоих случаях вы ошиблись.
Давайте посмотрим на пример. Как проиграть звуковой сигнал? Одна из возможностей заключается в использовании PInvoke и вызове Win32 метода Beep(). PInvoke позволяет управляемому коду вызывать неуправляемые функции. В VB6, Beep() имеет следующее объявление:
Beep(dwFreq as Long, dwDuration as Long) as Boolean
Тип Long в VB6 является 32-битным int.
Прототип Win32 будет иметь вид:
Beep(dwFreq as DWORD, dwDuration as DWORD) as Boolean
Теперь попробуем использовать Beep() в .NET. Примеры кода приведен ниже:
C#:
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:
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
Если вы скомпилируете это приложение, то увидите, что ничего не произошло. В чем же причина?
Несмотря на то, что CTS определяет типы данных, доступные для всех .NET языков, например System.Int32 или System.Double, каждый .NET язык определяет свои псевдонимы для этих типов. Например, C # использует int как псевдоним для System.Int32, в то время как VB.NET использует Integer. Эти псевдонимы, по всей видимости, соответствуют типам C++ (в случае C #) и VB6 (в случае VB.NET).
Таблица 1 показывает CTS-типы и их размеры для C# и C++.
CTS тип | Размер | C# псевдоним | Эквивалентный тип в C++ |
System.Int32 | 4 bytes | int | int или long |
System.Int64 | 8 bytes | long | _ _int64 |
System.Char | 2 bytes | char | WCHAR |
System.Double | 8 bytes | double | double |
Таблица 2 показывает CTS-типы и их размеры для VB.NET и VB6.
CTS тип | Размер | VB.NET псевдоним | Эквивалентный тип в 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 |
Как вы можете видеть из этих таблиц, размер long в C++ отличается от размера long в C#. Также размер Long в VB6 отличается от размера Long в VB.NET. Long в VB6 соответствует Integer в VB.NET. В нашем примере мы на самом деле передали 64-битный аргумент в функцию, которая ожидала 32-битный параметр, из-за чего наш метод не выполнился корректно. В примере ниже эта проблема исправлена.
В теории, отправка Integer в VB.NET не вполне является точным соответствием. Beep() принимает два беззнаковых 32-разрядных (DWORD) аргументов. Integer в VB.NET - это знаковый 32-разрядное число. Псевдонима для System.UInt32 в VB.NET нет (тип System.UInt32 не является CLS-совместимым). Можно использовать System.UInt32 в качестве типа параметра , передаваемого в метод Beep().
Новый вариант будет иметь вид:
C#:
[DllImport("kernel32")] public static extern bool Beep(uint dwFreq, uint dwDuration);
VB.NET:
Public Declare Function Beep Lib "Kernel32" ( _ ByVal dwFreq As Integer, ByVal dwDuration As Integer) _ As Boolean
Вывод
Помните о типах и их размерах, которые вы используете в .NET приложениях. Сайт http://pinvoke.net может помочь вам найти правильные соответствия.
P.S. Если вы хотите принять участие в переводе других gotchas, можете писать на электронную почту или в комментариях.
Компании из статьи
Microsoft Украина | Украинское подразделение компании Microsoft. |