Явное переполнение конверсии Int - PullRequest
1 голос
/ 15 марта 2012

Проблема

Когда я передаю значение в переменную int, где значение превышает максимальное значение для int, значение переменной int становится 0.

Фон

Я использую следующие шаги для извлечения моих данных.Я не использую блок try-catch без исключения.

Шаг 1

В моей WCF Service я получаю DataTable, используя IBM.Data.DB2.iSeries.iDB2DataAdapter.Fill(DataSet)

Шаг 2

Затем я преобразую DataTable в List<T>, используя код:

public static List<T> DataTableToList<T>(DataTable dt)
{
    List<T> tableEntity = new List<T>();

    foreach (DataRow row in dt.Rows)
    {
        T rowEntity = Activator.CreateInstance<T>();

        rowEntity.GetType().GetProperties().Where(o => dt.Columns.OfType<DataColumn>()
            .Select(p => p.ColumnName).Contains(o.Name)).ToList()
            .ForEach(o => o.SetValue(rowEntity, row[o.Name], null));

        tableEntity.Add(rowEntity);
    }

    return tableEntity;
}

с типом:

public class Client
{
    public int ID { get; set; }
    public string Name { get; set; }
}

Шаг 3

Я возвращаю его, используя метод службы WCF:

[OperationContract]
public string GetClients()
{
    List<Client> clients = new DB().RetrieveClients();
    return Tools.SerializeObjectToXML<List<Client>>(clients);
}

с вспомогательным методом для сериализации:

public static string SerializeObjectToXML<T>(T item)
{
    XmlSerializer xs = new XmlSerializer(typeof(T));
    using (StringWriter writer = new StringWriter())
    {
        xs.Serialize(writer, item);
        return writer.ToString();
    }
}

Шаг 4

Затем в клиентском приложении 1042 * я извлекаю его из справочника услуг 1044 * с привязкой по умолчанию WSHttpBinding с кодом:

List<Client> clients = Tools.DeserializeXMLToObject<List<Client>>(new SomeServiceClient().GetClients());

с помощью вспомогательного метода для десериализации:

public static T DeserializeXMLToObject<T>(string xmlText)
{
    if (string.IsNullOrEmpty(xmlText)) return default(T);
    XmlSerializer xs = new XmlSerializer(typeof(T));
    using (MemoryStream memoryStream = new MemoryStream(new UnicodeEncoding().GetBytes(xmlText)))
    using (XmlTextReader xsText = new XmlTextReader(memoryStream))
    {
        xsText.Normalization = true;
        return (T)xs.Deserialize(xsText);
    }
}

Вопрос

MSDN говорит , что:

Когда вы конвертируете из double или значение с плавающей запятой для целочисленного типа, значение усекается.Если полученное целое значение выходит за пределы диапазона целевого значения, результат зависит от контекста проверки переполнения.В проверенном контексте создается исключение OverflowException, тогда как в непроверенном контексте результатом является неопределенное значение типа назначения.

  • Почему значение Client.ID становится 0 когда значение из базы данных превышает максимально допустимое для int?
  • Это потому, что это непроверенный контекст?Если да, откуда мне знать?

Мой код находится на C #, framework 4, встроен в VS2010 Pro.

Пожалуйста, помогите, заранее спасибо.

Ответы [ 4 ]

2 голосов
/ 15 марта 2012

Здесь происходит что-то подозрительное. SetValue не выполняет приведение / преобразование (даже от uint до int, только что протестировано). Вам было бы гораздо лучше увеличить код ForEach в реальном foreach и отладить его.

Например:

foreach (var o in rowEntity.GetType().GetProperties().Where(o => dt.Columns.OfType<DataColumn>()
        .Select(p => p.ColumnName).Contains(o.Name)))
{
    if (o.Name == "ID")
    {
        // Put a breakpoint here
    }

    o.SetValue(rowEntity, row[o.Name], null));
}
1 голос
/ 15 марта 2012

По умолчанию переключатель компиляции арифметического переполнения отключен в Visual Studio.Чтобы включить его:

  • Щелкните правой кнопкой мыши проект и выберите Свойства .
  • Нажмите на вкладку Build .
  • Нажмите кнопку Дополнительно ... .
  • Установите флажок Проверка арифметического переполнения / недостаточного заполнения.
1 голос
/ 15 марта 2012

Я не знаю точно, где вы можете найти, если вы отмечены или не отмечены. Но это зависит от ваших опций компиляторов, как указано в http://msdn.microsoft.com/en-us/library/khy08726(v=vs.100).aspx

И, как сказал Торстен Диттмар, вы можете лучше использовать DataContract для простой отправки клиентов.

И если он переполнен, вы можете лучше использовать long для идентификатора вместо int. Таким образом, у него намного больше позиций (long == Int64). И если все ваши идентификаторы> 0, вы можете использовать unsigned int или unsigned, пока ваш Id. Без знака означает, что вместо того, чтобы иметь числа ниже нуля, он является только положительным и, следовательно, вдвое больше положительных позиций.

0 голосов
/ 15 марта 2012

Просто вопрос: почему вы передаете список в виде строки вместо выполнения следующих действий:

[OperationContract]
public Client[] GetClients()
{
    List<Client> clients = new DB().RetrieveClients();
    return clients.ToArray();
}

и объявляете класс Client следующим образом:

[DataContract]
public class Client
{
    [DataMember]
    public int ID;

    [DataMember]
    public string Name;
}

Также: Если тип ID в базе данных допускает значения, большие Int32.MaxValue, почему вы вообще используете Int32, а не Int64?

Что касается проверки переполнения: я знаючто использование Convert.ToInt32(Int64.MaxValue); вызывает исключение, а int i = (int)Int64.MaxValue - нет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...