Creating Policy Injection Matching Rules

Unity defines an interface named IMatchingRule, which all classes that implement matching rules must implement. This interface declares a single method named Matches that takes a MethodBase instance and returns a Boolean value.

public interface IMatchingRule
  bool Matches(MethodBase member);

Inside a concrete implementation of this interface, a custom matching rule class can access details of the current member (method or property) of the target object and determine whether Unity should add a handler pipeline to this member. The Matches method should return True if the current member matches the requirements of this matching rule; if the current member does not match the requirements of this matching rule, it should return False.

Remember that there may be several matching rules defined for a policy, and every one must return True when Unity calls their Matches method in order for Unity to add the handler pipeline to the target class member.

As an example of a matching rule, this following extract shows the TagAttributeMatchingRule class that implements the built-in tag attribute matching rule. This rule examines the current target object member, passed to the Matches method as a parameter, looking for any attributes of type TagAttribute, whose value matches the string value passed to the class constructor.

public class TagAttributeMatchingRule : IMatchingRule
  private readonly string tagToMatch;
  private readonly bool ignoreCase;

  // This constructor takes only the tag value.  
  public TagAttributeMatchingRule(string tagToMatch)
       : this(tagToMatch, false)
  { }

  // This constructor takes the tag value and the case-sensitivity setting. 
  public TagAttributeMatchingRule(string tagToMatch, bool ignoreCase)
    this.tagToMatch = tagToMatch;
    this.ignoreCase = ignoreCase;

  // The returns true only if a matching TagAttribute exists on this member.
  public bool Matches(MethodBase member)
    foreach (TagAttribute tagAttribute in 
             ReflectionHelper.GetAllAttributes<TagAttribute>(member, true))
      if (string.Compare(tagAttribute.Tag, tagToMatch, ignoreCase) == 0)
        return true;
    return false;

When Unity first creates an instance of the target object, it reads a list of matching rules from the configuration. For each rule it finds, it creates an instance of the appropriate class and passes to it as parameters the values of any attributes defined within the configuration for that matching rule. You can see that the constructors for the TagAttributeMatchingRule class accept the name of the attribute and a case-sensitivity value.

Internally, the TagAttributeMatchingRule class uses a separate helper class named ReflectionHelper that gets a list of all the attributes of type TagAttribute on the target member so that the Matches method can detect any that has the specified value—taking into account the setting of the ignoreCase property for this handler instance.

Notice that the TagAttributeMatchingRule class has a ConfigurationElementType attribute that defines the class (TagAttributeMatchingRuleData) that the configuration system uses to expose the data from the configuration to the matching rule. As an alternative approach, you can also use the CustomMatchingRuleData class in this attribute. This eliminates the need to create your own configuration data class; however, configuration information will be provided as a dictionary and will not be strongly typed.