我可以通过哪些方法确保字符串属性具有特定长度?

我已经创建了一些类,用于向我的数据库中的存储过程提供数据。 存储过程中的varchar参数具有长度规范(例如varchar(6) ,我想在将它们传递给存储过程之前validation所有字符串属性的长度。

有一个简单的,声明性的方法来做到这一点?


到目前为止,我有两个概念性想法:

属性

 public class MyDataClass { [MaxStringLength = 50] public string CompanyName { get; set; } } 

我不确定我需要使用哪些程序集/命名空间来实现这种声明性标记。 我认为这已经存在,但我不确定它在哪里以及它是否是最佳方式。

在属性中validation

 public class MyDataClass { private string _CompanyName; public string CompanyName { get {return _CompanyName;} set { if (value.Length > 50) throw new InvalidOperationException(); _CompanyName = value; } } } 

这似乎是很多工作,并且会让我当前简单的课看起来很丑陋,但我想它会完成工作。 这也需要大量的复制和粘贴才能做到这一点。

我会将此作为一个不同的答案发布,因为它与Code Contracts的特征不同。

可用于进行声明性validation的一种方法是使用字典或散列表作为属性存储,并共享实用程序方法以执行validation。

例如:

 // Example attribute class for MaxStringLength public class MaxStringLengthAttribute : Attribute { public int MaxLength { get; set; } public MaxStringLengthAttribute(int length) { this.MaxLength = length; } } // Class using the dictionary store and shared validation routine. public class MyDataClass { private Hashtable properties = new Hashtable(); public string CompanyName { get { return GetValue("CompanyName"); } [MaxStringLength(50)] set { SetValue("CompanyName", value); } } public TResult GetValue(string key) { return (TResult)(properties[key] ?? default(TResult)); } public void SetValue(string key, TValue value) { // Example retrieving attribute: var attributes = new StackTrace() .GetFrame(1) .GetMethod() .GetCustomAttributes(typeof(MaxStringLengthAttribute), true); // With the attribute in hand, perform validation here... properties[key] = value; } } 

您可以通过处理堆栈跟踪来使用reflection来获取调用属性,如此处所示 。 反映属性属性,运行validation, 瞧! 单线吸气器/设定器共享一个通用的validation程序。

另外,这种模式也很方便,因为您可以通过仅更新GetValueSetValue来设计类以使用其他类似字典的属性存储,例如ViewState或Session (在ASP.NET中)

另外需要注意的是,如果使用此方法,您可以考虑将validation逻辑重构为validation实用程序类,以便在所有类型之间共享使用。 这应该有助于防止您的数据类在SetValue方法中变得过于庞大。

好吧,无论你走到哪里,执行的东西看起来都像是你的第二种方法。 所以诀窍是让你的第一种方法成为你的第二种方法。

首先,它需要是[MaxStringLength(50)] 。 接下来,所有操作都是将一些数据添加到此类的Type对象中。 您仍然需要一种方法来使用该数据。

一种方法是二进制重写。 在编译之后(但在执行之前),重写器将读取程序集,查找该属性,并在找到它时,添加代码以进行检查。 零售产品PostSharp旨在完成这类产品。

或者,您可以在运行时触发它。 就像是:

 public class MyDataClass { private string _CompanyName; [MaxStringLength(50)] public string CompanyName { get {return _CompanyName;} set { ProcessValidation() _CompanyName = value; } } } 

这仍然很难看,但如果你有许多validation属性,它会好一点。

使用属性的第一种方法听起来不错。

通过inheritanceSystem.Attribute类来实现您的属性,并使用AttributeUsage属性标记您的类,以便在字段上设置您的属性。

然后,使用reflection,在将值发送到SP之前检查属性的存在和值。

这提供了比第二种方法更多的灵活性。 如果明天你决定让你的SP收到一个太长的字符串的前N个字符,你将不必修改所有代码,只修改解释该属性的代码。

框架中确实存在一些validation属性但我不会使用那些因为你可能暗示一些你不期望的行为,因为你无法以任何方式修改它们(如果你想要像[ MaxLength(50,true)]指定使用前50个字符是可以的。

这听起来像是一个商业规则。 所以我会将它放在公司类中(因为它是CompanyName),并在那里进行validation。 我不明白为什么如果你封装它就需要复制和粘贴。

一个属性或你的第二个例子应该没​​问题。 但是,该属性允许在具有字符串长度约束的其他类中重用。

虽然不完全相同,但我最近在MSDN文章中了解了.NET 4 Code Contracts 。 它们提供了一种方便而优雅的编码和分析代码假设的方法。 值得一看。