Skip to content

Advanced Queries

Ricardo Diaz edited this page Aug 7, 2017 · 2 revisions

On this page you will find information on the query capabilities in Fasterflect that go beyond what you can do with standard reflection.

These are the topics you'll find covered on this page:

Introduction

Before you read on please make sure that you have read the [Getting Started] page, in particular the section on how to customize the behavior of Fasterflect using [Flags][Flags].

Partial name comparisons

Fasterflect provides query extensions that allow you to pass in one or more names. All of these will by default use the string.Equals method to evaluate whether a member matches the name. You can change this behavior to string.Contains by passing in a Flags instance with the PartialNameMatch flag set.

Type type = obj.GetType(); 
// find the first static field containing a given substring
FieldInfo field = type.Field( "data", Flags.StaticAnyVisibility | Flags.PartialNameMatch  );
// find all instance methods containing the string "Handler" in their name
IList<MethodInfo> methods = type.Methods( "Handler", Flags.InstanceAnyVisibility | Flags.PartialNameMatch );

Name trimming

When an interface has been implemented explicitly on a type the members from that interface will be prefixed with the full namespace and interface name. Fasterflect gives you the option of stripping off this prefix before doing any name comparisons, which effectively allows you to search for a specific interface member without worrying about how it was implemented. To enable this behavior set the TrimExplicitlyImplemented flag.

// lets whip up a quick example of an explicit interface implementation
public interface ICount { int Count { get; } }
public class Counter : ICount { int ICount.Count { get; private set; } }
// assuming both are in the Fasterflect.Samples namespace we'd normally need to do this to find it:
Property property = typeof(Counter).Property( "Fasterflect.Samples.ICount.Count" );
// Fasterflect makes this easier
Property property = typeof(Counter).Property( "Count", Flags.InstanceAnyVisibility | Flags.TrimExplicitlyImplemented );

Excluding backing members

Fasterflect has the ability to filter out what it considers to be backing members, which are a couple of different things:

  • Virtual methods or properties that have an override lower in the hierarchy
  • Compiler-generated backing fields for automatic properties
  • Compiler-generated getter and setter methods for properties

Because Fasterflect returns members from the entire type hierarchy (unless you pass in Flags.DeclaredOnly), you would see duplicate entries for overridden virtual methods and properties. Setting the flag ExcludeBackingMembers enables filtering of these as well as the compiler-generated members.

// lets whip up a quick example of a type hierarchy with a virtual property and corresponding override
public class Person { public virtual string Name { get; protected set; } }
public class Employee : Person { public override string Name { get; protected set; } }

// the default behavior gives us duplicates although we can rely on the overridden being first in the result
IList<PropertyInfo> properties = typeof(Employee).Properties( "Name" );
Assert.AreEqual( 2, properties.Count );
Assert.AreEqual( typeof(Employee), properties.First().DeclaringType );
// getting rid of the duplicates is very easy
properties = typeof(Employee).Properties( flags, "Name", Flags.InstanceAnyVisibility | Flags.ExcludeBackingMembers );
Assert.AreEqual( 1, properties.Count );
Assert.AreEqual( typeof(Employee), properties.First().DeclaringType );

// now lets try the same exercise but this time looking for some additional member types
MemberTypes memberTypes = MemberTypes.Method | MemberTypes.Field | MemberTypes.Property;
IList<MemberInfo> members = typeof(Employee).Members( memberTypes );
Assert.AreEqual( 8, members.Count ); // Two Name properties, 2 backing fields and 4 get/set methods
// once again Fasterflect makes it easy to get to the member out of all these that you most likely want
members = typeof(Employee).Members( memberTypes, Flags.InstanceAnyVisibility | Flags.ExcludeBackingMembers );
Assert.AreEqual( 1, members.Count ); // just the overridden Name property from the Employee class

Excluding hidden (overridden or shadowed) members

Should you wish to ignore members that have been overridden or shadowed, simply set the ExcludeHiddenMembers flag and Fasterflect will filter these from the result.

The actual implementation of this works by comparing the names of members (and in case of methods, also their parameter signature; return type or generic parameters are not considered) to ensure that only one unique match is returned.

Excluding explicitly implemented interface members

Should you wish to ignore members that have been explicitly implemented, simply set the ExcludeExplicitlyImplemented flag and Fasterflect will filter these from the result.

// we'll reuse the example from above
public interface ICount { int Count { get; } }
public class Counter : ICount { int ICount.Count { get; private set; } }
// the following gives us a list of all properties including the explicitly implemented ones
IList<PropertyInfo> properties = typeof(Counter).Properties();
Assert.AreEqual( 1, properties.Count );
// with Fasterflect we can easily ignore these members
IList<PropertyInfo> properties = typeof(Counter).Properties( Flags.InstanceAnyVisibility | Flags.ExcludeExplicitlyImplemented );
Assert.AreEqual( 0, properties.Count );

[Flags]: (getting-started#bindingflags-values-defined-on-flags)