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

时间:2010-09-02 13:41:27

标签: c# .net vb.net validation

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

有一种简单的,声明性的方法吗?


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

属性

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

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

在属性中验证

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

这看起来像很多工作,并且会让我当前简单的课看起来很难看,但我想它会完成工作。为了做到这一点,还需要进行大量的复制和粘贴。

5 个答案:

答案 0 :(得分:2)

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

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

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

或者,您可以在运行时触发它。类似的东西:

public class MyDataClass 
{ 
     private string _CompanyName;

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

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

答案 1 :(得分:2)

我会将此作为不同的答案发布,因为它的特征与代码合同不同。

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

例如:

// 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<string>("CompanyName"); }

        [MaxStringLength(50)]
        set { SetValue<string>("CompanyName", value); }
    }

    public TResult GetValue<TResult>(string key)
    {
        return (TResult)(properties[key] ?? default(TResult));
    }

    public void SetValue<TValue>(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;
    }
}

您可以通过将堆栈跟踪设置为demonstrated here来使用反射来获取调用属性。反映属性属性,运行验证,瞧!共享一个通用验证例程的单行getter / setter。

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

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

答案 2 :(得分:1)

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

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

答案 3 :(得分:1)

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

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

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

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

框架中确实存在一些验证属性,但我不会使用这些属性,因为你可能会暗示一些你不期望的行为,因为你无法以任何方式修改它们(如果你想要的话,请说谎)像[MaxLength(50,true)]这样的东西来指定使用前50个字符就可以了。

答案 4 :(得分:0)

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