What ways can I ensure that a string property is of a particular length?

前端 未结 5 1603
北海茫月
北海茫月 2020-12-18 17:31

I\'ve created some classes that will be used to provide data to stored procedures in my database. The varchar parameters in the stored procs have length specif

相关标签:
5条回答
  • 2020-12-18 17:47

    It sounds like a business rule. So I would put it in a Company class (Since it is CompanyName), and do the validation there. I don't see why it would require copying and pasting if you have it encapsulated.

    Either an attribute or your second example should be fine. The attribute allows for reuse in other classes with string length constraints, however.

    0 讨论(0)
  • 2020-12-18 17:51

    The first method using attribute sounds good.

    Implement your attribute by inherit from the System.Attribute class and mark your class with AttributeUsage attribute to let your attribute being set on a field.

    Then, using reflection, check for presence and value of the attribute before sending the value to the SP.

    Thats provide you with lot more flexibility than the second method. If tomorow you decide to let your SP receive the first N chars of a too lengthly string, you won't have to modify all your code but only the one that interpret the attribute.

    There are indeed some validation attribute in the framework but I wouldn't use those one because you could implies some behaviour you don't expect and because you won't be able to modify then in any way (liek if you want something like [MaxLength(50, true)] to specify that using the first 5O chars is OK.

    0 讨论(0)
  • 2020-12-18 17:52

    I'll post this as a different answer, because it is characteristically different than Code Contracts.

    One approach you can use to have declarative validation is to use a dictionary or hash table as the property store, and share a utility method to perform validation.

    For example:

    // 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;
        }
    }
    

    You can get at the calling property using reflection by working up your stack trace as demonstrated here. Reflect the property attributes, run your validation, and voila! One-liner getter/setters that share a common validation routine.

    On an aside, this pattern is also convenient because you can design a class to use alternative dictionary-like property stores, such as ViewState or Session (in ASP.NET), by updating only GetValue and SetValue.

    One additional note is, should you use this approach, you might consider refactoring validation logic into a validation utility class for shared use among all your types. That should help prevent your data class from getting too bulky in the SetValue method.

    0 讨论(0)
  • 2020-12-18 18:07

    Though not exactly the same thing, I recently became aware of .NET 4 Code Contracts in an MSDN article. They provide a convenient and elegant way of encoding and analyzing code assumptions. It's worth taking a look at.

    0 讨论(0)
  • 2020-12-18 18:10

    Well, whatever way you go, what's executed is going to look like your second method. So the trick is getting your first method to act your second.

    First of all, It would need to be [MaxStringLength(50)]. Next, all that's doing is adding some data to the Type object for this class. You still need a way of putting that data to use.

    One way would be a binary re-writer. After compilation (but before execution), the rewriter would read the assembly, looking for that Attribute, and when finding it, add in the code for the check. The retail product PostSharp was designed to do exactly that type of thing.

    Alternately, you could trigger it at run-time. SOmething like:

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

    That's still quite ugly, but it's a bit better if you have a number of validation attributes.

    0 讨论(0)
提交回复
热议问题