I love Reflector, but sometimes I want to be able to explore through the Framework in more interesting ways. In this post I am going to use the program that I created last time to do some exploring.

How many types are there in the 2.0 version of the framework? Just click Go:
15834 – Wow! [Update: After 3.5 SP1 - 16375]

How many instances of the Async pattern are there in the .NET Framework? There are a bunch of ways to do this one. One way was shown in the picture last time.
Select Method, type ^Begin, press Add, select ParameterType, type AsyncCallback, press And, and click Go
831 [Update: 857]  The Name textbox uses regular expressions so the caret (^) before the word Begin just means that it should only match methods that start with Begin, rather than anywhere in the name (which is the default).

Looking through those it seems that lots of those are the possibly CPU bound delegate BeginInvoke pattern. Let’s filter out the delegates Leaving the expression the way it was last time add:
Select Inherits, type Delegate, check Not (checkbox), press And, and click Go:
233 [Update: 247]
So I guess that means there are about 600 delegates? I will double check that in one second.

First it looks like a lot of the instances of the async pattern that are left inherit from Stream, lets filter those out as well. Again leaving the expression the way it is:
Select Inherits, type Stream, check Not (checkbox), press And, and click Go:
68 [Update: 76] and one of those is Stream itself. Go ahead and have a look – the ones left have a lot of diversity: SqlCommand, LdapConnection, Dns lookup, WebRequest, HttpListener, tons of Socket stuff, MSMQ, .NET Remoting, System.Transactions, and HttpAsyncHandler. All provided for you free of charge in the .NET framework itself.

Now lets go back to those delegates:
Press Clear, select Inherits, type Delegate, and click Go:
595 [Update: 607] – close enough that I believe it :)

Another question that I wanted answered was what are the generic delegates? Leaving the expression the way it is:
Select Type, type `(backtick), and click Go. The backtick is the way that generic types are represented in the IL. Here we see a really small list, but all of them are extremely useful: Action ,Predicate, Comparison, Converter, etc.

UsingReflectForEntities

I played around a little more and found lots of other oddities. For example: I was searching for Trees and I found an RBTree in the System.Data assembly – WTF? I have attached the finished project – happy hunting!

Now that I teach the Essential .NET class for DevelopMentor, I find myself scouring the MSDN reference documentation looking for specific types. After doing this for an hour or so, I got to thinking – there has to be a better way. So I started out with a fairly simple application which used reflection and a simple string.Contains to browse for certain classes in the framework. Because of the naming convention of ending the class name with the name of the class you are inheriting from this worked quite nicely.

The form looked like this:

ReflectForEntities1

However, I soon needed more features like:

  • looking for certain methods
  • being able to delete items from the tree manually, when I found they didn’t apply
  • displaying the count of elements found at any location

So I kept adding functionality.

Then I needed the ability to combine multiple filters at one time, like looking for Asynchronous Programming Model (APM) methods. This is where things got interesting. To do this I created a set of filters. A filter is really just class that stores some information and contains boolean function that acts upon a type to figure out if it should be included in the result set. I created in interface for this purpose which looked like this:

interface IFilter
{
	bool IsTypeAllowed(Type t);
}

The implementation of this interface is pretty easy. Basically checking each the name of each type against a set of regular expressions

public bool IsTypeAllowed(Type t)
{
	if ((Type & TypeSearchType.Namespace) != 0)
	{
		if (t.Namespace == null) return false;
		if (!Regex.Match(t.Namespace).Success)
			return false;
	}
	if ((Type & TypeSearchType.Type) != 0)
	{
		if (!Regex.Match(t.Name).Success)
			return false;
	}
	if ((Type & TypeSearchType.Member) != 0)
	{
		found = false;
		foreach (MemberInfo mi in t.GetMembers())
		{
			if (Regex.Match(mi.Name).Success)
				found = true;
		}
		if (!found) return false;
	}
	return true;
}

This too worked really well until I needed to filter out methods. I needed a way of returning a subset of the methods on the type which met the filter criteria. To accomplish this I had to hackmodify the interface to look like this:

interface IFilter
{
	bool IsTypeAllowed(Type t, out List<MemberInfo> mis);
}

Then I had to modify the behavior to look like this (I added inheritance checking and parameter type checking while I was in there poking around)

public bool IsTypeAllowed(Type t, out List<MemberInfo> mis)
{
	mis = null;
	if (filterNullNamespaces && t.Namespace == null) return false;

	if ((Type & TypeSearchType.Inherits) != 0)
	{
		if (!IsBaseTypeAllowed(t))
			return false;
	}
	if ((Type & TypeSearchType.Namespace) != 0)
	{
		if (!Regex.Match(t.Namespace).Success)
			return false;
	}
	if ((Type & TypeSearchType.Type) != 0)
	{
		if (!Regex.Match(t.Name).Success)
			return false;
	}
	if ((Type & TypeSearchType.Member) != 0)
	{
		if (!IsMemberAllowed(t, out mis))
			return false;
	}
	return true;
}

bool IsBaseTypeAllowed(Type t)
{
	bool foundType = false;
	while (t.BaseType != null)
	{
		t = t.BaseType;
		if (Regex.Match(t.Name).Success)
		{
			foundType = true;
			break;
		}
	}
	return foundType;
}

bool IsMemberAllowed(Type t, out List<MemberInfo> mis)
{
	mis = null;
	bool foundType = false;
	foreach (MemberInfo mi in t.GetMembers())
	{
		bool foundMethod = false;
		if (((mi.MemberType & (MemberTypes.Constructor | MemberTypes.Method)) != 0) &&
			(Type == TypeSearchType.ParameterType))
		{
			MethodBase mb = (MethodBase)mi;
			foreach (ParameterInfo pi in mb.GetParameters())
			{
				if (Regex.Match(pi.ParameterType.Name).Success)
				{
					foundMethod = true;
					break;
				}
			}
		}
		else
		{
			foundMethod = Regex.Match(mi.Name).Success;
		}

		if (foundMethod)
		{
			if (mis == null)
				mis = new List<MemberInfo>();
			mis.Add(mi);
			foundMethod = false;
			foundType = true;
		}
	}
	return foundType;
}

Then on to the boolean logic piece. There are essentially 3 binary operators (that I cared about): NOT, AND, and OR. NOT is a unary operator, whereas both AND and OR are binary. I chose to create three new classes that contain the simple Filter that I had created earlier. The benefit of containing rather than inheriting/overriding is that I was able to encapsulate all of the logic in one and only one place.

The other problem was that regardless of how complicated the final expression was I wanted to be able to perform a NOT on it to produce the sets complement. To do that I had to Add another method on the interface so that all filter types could produce a NOT. The result of all that refactoring looked like this:

	class NotFilter : IFilter
	{
		IFilter subFilter;

		public NotFilter(IFilter subFilter)
		{
			this.subFilter = subFilter;
		}

		public IFilter CreateNot()
		{
			return subFilter;
		}

		public bool IsTypeAllowed(Type t, out List<MemberInfo> mis)
		{
			mis = null;
			List<MemberInfo> subMis;
			bool subAllowed = subFilter.IsTypeAllowed(t, out subMis);
			if (subMis != null)
			{
				mis = new List<MemberInfo>();
				foreach (MemberInfo mi in t.GetMembers())
				{
					if (!subMis.Contains(mi))
						mis.Add(mi);
				}
			}
			return !subAllowed;
		}

		public override string ToString()
		{
			return "!" + subFilter.ToString();
		}
	}

	class AndFilter : IFilter
	{
		IFilter sub1;
		IFilter sub2;
		public AndFilter(IFilter sub1, IFilter sub2)
		{
			this.sub1 = sub1;
			this.sub2 = sub2;
		}

		public IFilter CreateNot()
		{
			return new OrFilter(sub1.CreateNot(), sub2.CreateNot());
		}

		public bool IsTypeAllowed(Type t, out List<MemberInfo> mis)
		{
			mis = null;
			List<MemberInfo> mis1;
			List<MemberInfo> mis2 = null;
			bool allowed =
				sub1.IsTypeAllowed(t, out mis1) &&
				sub2.IsTypeAllowed(t, out mis2);
			if (allowed)
			{
				if (mis1 != null)
					mis = mis1;
				if ((mis == null) && (mis2 != null))
					mis = mis2;

				if ((mis1 != null) && (mis2 != null))
				{
					mis = new List<MemberInfo>();
					foreach (MemberInfo mi in mis2)
					{
						if (mis1.Contains(mi))
							mis.Add(mi);
					}
				}
			}
			return allowed;
		}
		public override string ToString()
		{
			return string.Format("({0}) && ({1})", sub1.ToString(), sub2.ToString());
		}
	}

	class OrFilter : IFilter
	{
		IFilter sub1;
		IFilter sub2;
		public OrFilter(IFilter sub1, IFilter sub2)
		{
			this.sub1 = sub1;
			this.sub2 = sub2;
		}

		public IFilter CreateNot()
		{
			return new AndFilter(sub1.CreateNot(), sub2.CreateNot());
		}

		public bool IsTypeAllowed(Type t, out List<MemberInfo> mis)
		{
			mis = null;
			List<MemberInfo> mis1 = null;
			List<MemberInfo> mis2 = null;
			bool allowed1 = sub1.IsTypeAllowed(t, out mis1);
			bool allowed2 = sub2.IsTypeAllowed(t, out mis2);
			bool allowed = allowed1 || allowed2;
			if (allowed)
			{
				if (mis1 != null)
					mis = mis1;
				if ((mis == null) && (mis2 != null))
					mis = mis2;

				if ((mis1 != null) && (mis2 != null))
				{
					foreach (MemberInfo mi in mis2)
					{
						if (!mis.Contains(mi))
							mis.Add(mi);
					}
				}
			}
			return allowed;
		}
		public override string ToString()
		{
			return string.Format("({0}) || ({1})", sub1.ToString(), sub2.ToString());
		}
	}

I also had to refactor the UI a little bit. The form now looks like this:

ReflectForEntities2

Notice that I got a little bit carried away and placed a Flags button on the UI (initially disabled).

There was one caveat. If you were to give me any random boolean expression, I wouldn’t necessarily be able to express it in the program. Expressed in tree form, my program could only produce expressions that looked like:

ExpressionTree1

However, the program was working great; I had no major flaws in the design (that I could see), and I was able to perform some pretty nifty expressions which I will discuss in another blog entry.