Is there a type safe way to reference a class/property in an attribute?

Let's say I have a class, PersonAddressValidator that takes in a person object and an address object and does some validation (this isn't really the problem I am modelling so bear with me if this seems overly simplistic).

class PersonAddressValidator : IPersonAddressValidator
{
    bool Validate(Person p, Address a)
    {
        // sample "validation"
        if (p.FirstName.StartsWith("a") && a.ZipCode == 91402)
        {
            return false;
        }
    }
}

Let's also assume there are many different objects implementing IPersonAddressValidator for different business rules.

In the above case, I am referencing the "FirstName" of person and "ZipCode" of address. I'd like to somehow note that this class is using these properties of their respective objects. The reason I'd like to do this is so that if someone wanted to run this validation against all people/address combinations, they could easily see the relevant properties that are causing the validation class to pass or fail.

I was thinking this is something I could do with an attribute:

[ValidationAttribute(typeof(Person), "FirstName")]
[ValidationAttribute(typeof(Address), "ZipCode")]
class PersonAddressValidator : IPersonAddressValidator
{
    bool Validate(Person p, Address a)
    {
        // sample "validation"
        if (p.FirstName.StartsWith("a") && a.ZipCode == 91402)
        {
            return false;
        }
    }
}

An obvious issue with this approach is that the property I reference in the second part of the ValidationAttribute is not type-safe. Just curious if there is a better way to do solve this problem (attributes or otherwise)?

Thanks.

Jon Skeet
people
quotationmark

There's nothing to make it absolutely safe at compile-time from a C# language perspective, no.

There are things you can do to help though. In C# 6, you can use the nameof operator, which makes it refactoring-friendly and makes it more obvious if you're doing something stupid:

[ValidationAttribute(typeof(Address), nameof(Address.ZipCode))]

Next, you can validate each attribute usage within unit tests. That's fairly simple, and keeps you pretty safe if you're good at running your tests regularly :)

If you're feeling more adventurous, you could write a Roslyn Code Diagnostic which will validate that each use of ValidationAttribute is right - and possibly even check that it uses the nameof syntax too. That's rather more code to write than the unit test, but it will give you "editing time" support.

people

See more on this question at Stackoverflow