Search code examples
c#validationmaxlength

Get value of an Attribute-decorated property


i want to make some validations in a class, so i thought I could use attributes. Like this:

public class someClass
{
    [Lenght(200)]
    public string someStr { get; set; }
}
[AttributeUsage(AttributeTargets.All, Inherited = false, AllowMultiple = true)]
sealed class Lenght  : Attribute
{
    public Lenght(int Lenght)
    {
         //some code   
    }
}

But I know that I can't do it, because this is not how attributes work. And, if there is a way, it would use some kind of heavy reflection and kludges that I want to avoid.

The validation I want to do is like this:

public class someClass
{

    public string someStr
    {
        get
        {
            return _someStr;
        }
        set
        {
            if (value.Length > 200)
            {
                throw new Exception("Max Length is 200!");
            }
            else _someStr = value;
        }
    }
    private string _someStr { get; set; }
}

But I want to do it faster, without all this code. I want as fast as using an Attribute.

There is a way i could do it?


Solution

  • Normally you would not do stuff like this with an attribute, but it is possible, although not recommendable. Use at your own risk :) (you will let loose hell if the property is not decorated with the LengthAttribute :) )

        public interface AttributeValidator
        {
            void CheckOk(object value);
        }
    
        public class LenghtAttribute : Attribute, AttributeValidator
        {
            public int MaxLength { get; private set; }
            public LenghtAttribute(int lenght)
            {
                this.MaxLength = lenght;
            }
    
            public void CheckOk(object value)
            {
                var str = value as string;
                if (str != value)
                    throw new Exception("Not a string!");
    
                if (str != null && str.Length > MaxLength)
                    throw new Exception("To long!");
            }
        }
    
        public class DoesNotContain : Attribute, AttributeValidator
        {
            public string Chars { get; private set; }
            public DoesNotContain(string chars)
            {
                this.Chars = chars;
            }
    
            public void CheckOk(object value)
            {
                var str = value as string;
                if (str != value)
                    throw new Exception("Not a string!");
    
                if (str != null && Chars.Any(c => str.Contains(c)))
                    throw new Exception("Contains forbidden character!");
            }
        }
    
        public class SomeClass
        {
            private string _someString;
    
            [Lenght(200)]
            [DoesNotContain("$#2")]
            public string SomeString
            {
                get { return _someString; }
                set
                {
                    Utils.Validate("SomeString", this, value);
                    _someString = value;
                }
            }
        }
    
        public static class Utils
        {
            public static void Validate(string property, object instance, string value)
            {
                var validators = instance.GetType().GetProperty(property)
                    .GetCustomAttributes(false).OfType<AttributeValidator>();
    
                foreach (var validator in validators)
                    validator.CheckOk(value);
            }
        }
    

    EDIT I've extended the example. Still a horrible solution, but it works.