简体   繁体   中英

Using custom attribute for non negative validation using reflection

I am new to c# and trying to grasp the use of custom attributes and how to use it for data validation using reflection. For example, if you have to see if collected year data has four digits and it is non negative number. How can we use custom attribute and reflection to implement such logic.

Appreciate if sample code is provided

You can do something similar like Data Annotation Validators . The big picture is like this:

  1. You define an object with some fields (the fields are decorated with attributes)
  2. Use validator that validates an object that has fields decorated with those attributes.

The model class could be like this

class Person
{
    [StringNotNullOrEmpty]
    string FirstName { get; set; }

    [Range(Min = 0, Max = 100)]
    int Age {get; set; }
}

The validator is kinda like this:

class Validator
{
    public IEnumerable<FieldValidationResult> ValidateObject(object ob)
    {
        List<FieldValidationResult> list = new List<FieldValidationResult>();

        var properties = ob.GetType().GetProperties();

        foreach(var property in properties)
        {
            var res = ValidateField(ob, property);

            list.Add(res);
        }

        return list;
    }

    private FieldValidationResult ValidateField(object ob, PropertyInfo prop)
    {
        var attributes = prop.GetCustomAttributes();

        foreach(var att in attributes)
        {
            if (att is StringNotNullOrEmptyAttribute)
            {
                string strVal = prop.GetValue(ob) as string;

                if (string.IsNullOrEmpty(strVal))
                    return new FieldValidationResult("Field {0} can not be empty")

                return null;
            }

            if (att is RangeAttribute)
            {
                // validate range attribute
                   var rangeAtt = (RangeAttribute)att;
                   int intVal = (int)prop.GetValue(ob);

                    if (rangeAtt.Min > intVal || rangeAtt.Max < intVal)
                              return new FieldValitaionResult("Field {0} must be between {1} and {2}, prop.Name, rangeAtt.Min, rangeAtt.Max);

                           return null;
            }
        }
    }
}

And use it like this:

Person p = new Person();
p.FirstName = "";
p.Age = 10;

Validator validator = new Validator();

var validationResults = validator.ValidateObject(p);

You can declare a custom attribute like this...

public class MyAttribute : Attribute
{
    public MyAttribute(bool b)
    {
        MustBePositive = b;
    }
    public bool MustBePositive { get; set; }
}

This attribute has a boolean indicating whether the value must be positive.

You can then decorate members with it like this...

    [MyAttribute(true)]
    public int MyInt { get; set; }

A complete validation method for this would be...

public class Data
{
    [MyAttribute(true)]
    public int MyInt { get; set; }
    public void Validate()
    {
        foreach (PropertyInfo pi in typeof (Data).GetProperties())
        {
            var atts = pi.GetCustomAttributes(typeof (MyAttribute), false).FirstOrDefault();
            if (atts != null)
            {
                var myAtt = atts as MyAttribute;
                if (myAtt != null)
                {
                    if (myAtt.MustBePositive)
                    {
                        var propValue = (int)pi.GetValue(this);
                        if (propValue < 0)
                        {
                            Console.WriteLine(@"Invalid");
                        }
                    }
                }
            }
        }
    }
}

This method will print "Invalid" when the MyInt property is negative. The Validate method itself queries the instance for properties decorated with MyAttribute. It gets the instance value and tests it.

There are optimizations that can be implemented on the Validate method such as doing all the lookups at initialization time, but the above code gives a fully working example.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM