User Story
Using reflection, I'd like to test for the existence of an specific member info on a specific type about which I know everything. I'll then then reflect over properties unrelated to the info's identity. Usually, looking at custom attributes. I assert this pattern represents is a first class scenario.
Fast
I want to do this in the fastest way possible. To that end, I expect that
- Reflection not waste cycles walking the hierarchy. I only want an info defined on a specific type.
- Reflection not waste cycles doing any binding. I only want a specific member (e.g. I don't want
void M(object o)
if I ask for a method M
with argument string
).
Light
I want to do this using the least memory (fewest info activation/caching) possible. To that end, I expect that
- If the member exist than reflection will have only activated that single member info.
- If the member does not exist then reflection has not allocated any member infos.
This necessarily means I can pass the API everything need to uniquely identify the member info in which I'm interested. I say "necessarily" because it that's not the case then I'll be returned a list of infos which I'll have to filer which already means that reflection has allocated more infos than necessary.
Easy
As a first class scenario, the API signatures should form the necessary and sufficient set for identifying an arbitrary info. To that end, the API signatures should not take parameters suited to other purposes. For example, they shouldn't take BindingFlags
which has values like CreateInstance
which are not necessary for identifying an info.
Accessible
As a first class scenario, I expect the APIs be accessible from an instance of Type
. To that end, I expect the APIs should live on, or be extension methods of, Type
. The API should not live on TypeInfo
.
Summary
In summary, basically, I should not have to take a "swiss-army-knife" API, like those that take BindingFlags
, and have to research each parameter to figure out how to most efficiently retrieve a member info about which I know everything. Furthermore, this scenario is hard enough to achieve given the existing API that it deserves a first class API.
Proposal
Add the following:
public static class TypeExtensions
{
public static Type GetDeclaredNestedType(this Type type,
string name);
public static ConstructorInfo GetDeclaredConstructor(this Type type,
Type[] parameters = null);
public static PropertyInfo GetDeclaredProperty(this Type type,
string name,
Type[] parameters = null,
Type propertyType = null);
public static FieldInfo GetDeclaredField(this Type type,
string name,
Type fieldType = null);
public static EventInfo GetDeclaredEvent(this Type type,
string name,
Type eventType = null);
public static MethodInfo GetDeclaredMethod(this Type type,
string name,
Type[] parameters = null,
Type[] genericParameters = null,
Type returnType = null);
}
Rational
Fast & Light
These are the fastest lightest signatures that fulfill the user story as they represent the necessary and sufficient set to uniquely identify their respective member infos (modulo signature modifiers, see below); Or, more formally, I assert that if any of these parameters are removed then I can construct an assembly containing an info which can no longer be uniquely identified (again modulo signature modifiers). For example, without fieldType
I can construct an assembly using ILAsm that contains a class with two field with the same name but different types neither of which could any longer be uniquely identified by GetDeclaredField
.
Accessible & Easy
These are accessible as they live on TypeExtensions. They are easy to use because they were specifically chosen as the set necessary and sufficient to fulfill the user story.
Implementation
Many of these APIs can simply call a existing swiss-army-knife API however some require new functionality be added to a existing swiss-army-knife APIs. The APIs will be addressed from simplest (functionality already exists) to most complicated (functionality must be added).