• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录
微软(北京).Net俱乐部-H2O、winnerzone
一个战士一旦穿上军装拿起武器就已经做好了战斗的准备,他将被派往无数战火纷飞的战场,每一次都会有生命的危险。
但是一旦他活下来了,那些都将成为光荣的历史被讲述和回忆。对于一个新兵,危险和机遇并存,机遇大于危险和压力。
博客园    首页    新随笔    联系   管理    订阅  订阅

【翻译】数据转换和验证

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

摘要
      这篇文章介绍了一个关于数据转换和验证时的技巧、遇到的问题。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

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 上取保您的正确数据。


WINNERZONE
posted @ 2008-07-24 10:07  H2O、winnerzone  阅读(3356)  评论(13)    收藏  举报
刷新页面返回顶部
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3