【翻译】数据转换和验证

摘要
      这篇文章介绍了一个关于数据转换和验证时的技巧、遇到的问题。Brian(作者)检查数据和 Nullable 类型转换中涉及的技术,以及相关的C# 代码。他还提供了一个 String 概要,Data Type 范围,和在 ASP.NET 中使用不同的方式限制 input 数据。

by Brian Mains

介绍

      数据类型转换不总是会隐式发生的。为了避免编写大量代码,我已经包括一种用来分析一定范围的数据值的技巧。我也讨论了关于一些总所周知的数据项的转换和验证。 

数据类型转换

      当从一个外部资源(例如:一个文件)传入数据时,需要一个解释数据内容的实体类。例如,在数据库系统中,.NET 的每个数据具有一个映射到他们的 SQL Server 或 Oracle 数据库等效的数据类型。

      当从一个组件(流读取或者数据表)读取数据时,传入系统的数据值可能为1。尽管他是一个数字,基础数据类型可以是一个string,然而 "1"(字符串) 不等于 1(数字) 。获得一个 "1" 的正确类型再进行对比。int.Parse 或者int.TryParse 方法可以将值转换成数字类型。

      有时一个表的数据使用了许多不同类型(例如:Profile 表),所有的值都存储在一个 Nvarchar 或者 Varcher 数据列中。因为 (Nvarchar 和 Varchar) .NET 中的基础类型是 string,而存储的这些值不仅仅只转换成 DateTime 或者 Int 类型。只要存储的值是有效的 string 类型,使用 DateTime.Parse 或者 int.Parse 进行转换(使用 TryParse 进行转换可以防止异常发生)时,就有可能会引发异常。

      在执行类型转换时,我将使用一个 Helper 的方法将值进行相应的类型转换。例如,假设从一个基础集合(从文件或者数据库中填充的集合)中你使用 Key 来检索一个项,使用下面的方法将数据动态的转换为泛型类型。

Listing 1

ExpandedBlockStart.gif ContractedBlock.gif private  T GetValue < T > ( string  key)  { }

      然后从一个集合中获取一个值,首先检查确保该数据不是 null ,也不是数据库中的 null 。如果是这些值,返回默认值(T)。这里返回指定的类型默认值是为了不会因为类型的不同而引发异常。例如类型 null 被返回。而对于值类型,最小值没有被返回 (整数返回 0)。

      接下来的一步判断基础 Value 是否是指定类型。如果 Value 完全匹配泛型类型,它将被返回。

Listing 2

if  (value  is  T)  return  (T)value;

      当返回泛型类型时,有时 User 想要一个 string  ,不考虑基础类型是 Int,Decimal,DeteTime,等等。下面展示了一个绕过编译器错误的小技巧。你不能简单的去调用 ToString() 来返回 Value。即使该类型 在您的逻辑中 匹配,编译器不知道这种情况将始终为一个字符串,因为编译器只处理泛型类型 T ,并不知道基础的表示形式。

Listing 3

// If the type of T is a string type, then process this
object  stringValue  =  value.ToString();
return  (T)stringValue;

      对于所有类型转换,可以使用 Convert.ChangeType 来将对象转换成相应的类型。DateTime,string,这样的大多数值类型支持使用 Convert.ChangeType 进行类型转换。但是,在调用之前确保可以进行类型转换,因为如果转换不成功将引发异常。

      我发现在这个方法中的一个变化:Null 类型。Null 类型不支持使用 Convert.ChangeType 进行转换,并且我想到下面一种替代方法。

Nullable 类型转换

      在C# 中 Nullalbe 类型表示为 <type>?,如 int? 。像 int? 这样的许多参数和字段类型表示为支持一个直接返回 null 的 Value。此外,Null 对象的定义添加了两个其他属性:HashValue 和 Value。如果该 Value 是 Null 时,您访问这个 Value 属性,将引发异常,所以您要检查这个 HasValue 的值不为 Null 。另一种方法是调用 GetValueOrDefault() 方法。

      Nullable 类型用泛型表示为 Nullable<int>,使用下面的语法构造一个新的 Nullable 对象。

Listing 4

new  Nullable < int > ( null );
new  Nullable < int > ( 1 );

      Nullable 值将转换成基类型作为引用类型被传入,这必须进行特殊处理。在以前这样做是不起作用的。若要确定是 Nullable 类型,使用下面的方法。我必须感谢微软;我曾在检查 JSON 序列化进程的代码时因为 Nullable 而报错。

Listing 5

if  ( typeof (T).IsGenericType  &&   typeof (T).GetGenericTypeDefinition()  ==   typeof (Nullable <> ))

      理想情况是使用 Null 类型的构造函数,但是我们需要提取泛型类型并传入一个新的 Nullable 值。例如,下面的代码中,Nullable<int> 是一个引用类型,Generic Argument 引用一个值类型。

Listing 6

Type parameterType  =   typeof (T).GetGenericArguments()[ 0 ];
Type nullableType 
=   typeof (Nullable <> ).MakeGenericType(parameterType);
return  (T)Activator.CreateInstance(nullableType, 
                             new   object []  { Convert.ChangeType(value, parameterType)} );
 
 

      创建一个 Nullable 类型的实体,获取 Nullable<> 类型,使用 MakeGenericType 方法创建一个 Nullable<int> 。   CreateInstance 创建 Nullable 类型的实例,安全的使用 Convert.ChangeType 将 Value 转换成 Int 类型。

      前面已经讲到,因为 Nullable 类型不能转换,我们不能简单的使用 Convert.ChangeType(value, Nullable<int>) 来进行转换。那将会抛出异常。要是想处理这种情况,使用 GetGenericArguments 方法来获取 Int 类型。该方法动态的生成 Nullable 类型,并分配给 NullableType 字段。最后,传入整数构造一个新的 Nullable 类型的类。

String 范围

      在 .NET Framework 中的 String 支持各种字符集和语言。这非常棒,因为 SQL Server 中支持不同语言和区域。虽然 .NET Framework 不需要验证 String 的长度,这意味着即使 SQL Server 里是 50 个字符长度的字段,在 .NET Framework 中的 String 也是无限的。

      传入到数据库之前,我们要验证 String 长度是很重要的。在数据上这样的错误是很令人讨厌,并很难识别。因为通常返回到调用方的错误信息不是具体的错误信息,它没有告诉你哪个字段超出了长度的限制。

      在 .NET UI Controls 中允许用户限定输入的 String 最大长度。它在服务器端进行检查;但是如果是硬编码一个字符串长度,会使得它变得难以维护。(因为对该数据库的任何更改影响在用户界面)

Date Type 范围

      在 .NET Framework 中的 Date 类型支持 SQL Server 数据库,但是你要注意 Date 值的范围。例如,.NET Framework 支持的最小日期值是 1/1/0001,在 SQL Server 中并不支持这个值。

      在 SQL Server 中,datetime 数据类型的最小值是 1/1/1753 ,并且 smalldatetime 数据类型的最小值是 1/1/1900。在最大值范围中,smalldatetime 是不适合用 DateTime.MaxValue 属性来设置的。 

      如果外部超出范围的 Date 被传入,一个 DateTime 溢出异常将被抛出,这显然是使用数据转换时的一个问题。此外,String 类型没有任何长度限制,不能很方便的捕获,除非手动验证。

数据输入

      在 ASP.NET 中,尽管数据的类型不同,但通常是通过 textbox 控件输入的。一个文本框可以用于输入名字,数字,日期,其他类型。结合 AJAX control toolkit 一起使用,会很容易的限制文本框输入的字符类型。

      当尝试从 textbox 中获取 Value 并转换成所需要的数据类型时,需要注意些。例如,当一个 DateTime 数据类型,输入时必须进行检查以确保是正确的。如果用户输入以下值:13/13/2008,1/113/2008,4/32/2008 ,当这些值被传递给 DateTime.Parse 或者 Convert.ToDateTime 进行转换时,会引发异常。

      最好是使用 DateTime.TryParse 来转换日期值。如果日期值是无效的 TryParse 将返回一个空值,并且返回 false。数字类型的值也同样适用;至少使用 TryParse 转换,是一种防止出错的好方法。

      理想情况下,最好在输入值的地方限制或阻止无效的输入。AJAX control toolkit 中包含了限制控件文本输入的扩展控件。例如,MaskedEditExtender 扩展控件可以限制必须以货币、日期、数字类型 input。

Listing 7

< ajax:MaskedEditExtender  id ="ext"  runat ="server"  Mask ="99/99/9999"  MaskType ="Date"   />

      作为一种替代方案,FilteredTextBoxExtender 扩展控件可以限制 input 到文本框的字符类型。它可以控制 input 的只能是数字、小写字母、大写字母、自定义字符、任意组合。以下代码是筛选掉数字以外的字符,但是允许 input 一个小数点。

Listing 8

< ajax:FilteredTextBoxExtender  id ="ext"  runat ="server"     FilterType ="Numbers,Custom"  ValidChars ="."   />

      您同样也可以使用 Validation 控件。Validation 控件可以限制无效的 input 。例如,即使 FilteredTextBoxExtender 筛选掉了数字和小数点以外的值,他将允许多个小数点。下面的 RegularExpressionValidator 控件将阻止录入多个小数点。

Listing 9

< asp:RegularExpressionValidator  id ="rev"  runat ="server"  ControlToValidate ="txt"
ErrorMessage
="Enter a valid dollar amount"  ValidationExpression ="\d+\.\d{2}"   />

So plan your interface accordingly.

结论

      数据转换看起来不是那么简单,最重要的是基础数据的类型。可以使用单个方法将值进行转换。也要在 UI 上取保您的正确数据。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值