问题
当我将值传递给int
变量,其中该值超过了int
的最大值时,int
变量的值变为0
。
背景
我使用以下步骤来检索我的数据。我不会在不抛出异常的情况下使用任何try-catch块。
步骤1
在WCF服务中,我使用IBM.Data.DB2.iSeries.iDB2DataAdapter.Fill(DataSet)
检索DataTable
步骤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
然后在客户端应用程序中,我从服务引用中检索它,默认绑定为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或float值转换为整型时,该值将被截断。如果得到的整数值在目标值的范围之外,则结果取决于溢出检查上下文。在已检查的上下文中,会引发OverflowException,而在未检查的上下文下,结果是目标类型的未指定值。
- 当数据库中的值超过int允许的最大值时,为什么
Client.ID
的值变成0
- 是因为它是一个未检查的上下文吗?如果是,我怎么知道
我的代码是C#,框架4,在VS2010Pro中构建的。
请帮忙,提前谢谢。
这里发生了一些可疑的事情。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));
}
默认情况下,Visual Studio中的算术溢出编译器开关处于关闭状态。启用:
- 右键单击项目,然后单击属性
- 单击构建选项卡
- 单击高级…按钮
- 选中"检查算术上溢/下溢"复选框
如果选中或未选中,我不知道你能在哪里找到。但这取决于您的编译器选项,如中所述http://msdn.microsoft.com/en-us/library/khy08726(v=vs.100).aspx
正如Thorsten Dittmar所说,您可以更好地使用DataContract来轻松发送客户端。
如果它溢出,您可以更好地使用long
作为id,而不是int
。这样它就有了更多的位置(long == Int64
)。如果你的所有Id都>0,你可以使用无符号int或无符号long作为你的Id。无符号意味着它不是数字也低于零,而是正的,因此是正位置的两倍。
- Int32
- Uint32
- Int64(长)
- Uint64(ulong)
只是一个问题:为什么要将列表作为字符串传输,而不是执行以下操作:
[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
不会。