Added container accessor to Castle.Core
[castle.git] / Tools / Castle.DynamicProxy2 / Castle.DynamicProxy / Generators / MethodFinder.cs
blob14958b1677017c215a95e56eebbc8ae588cbecf9
1 // Copyright 2004-2007 Castle Project - http://www.castleproject.org/
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
15 namespace Castle.DynamicProxy.Generators
17 using System;
18 using System.Collections;
19 using System.Collections.Generic;
20 using System.Reflection;
22 /// <summary>
23 /// Returns the methods implemented by a type. Use this instead of Type.GetMethods() to work around a CLR issue
24 /// where duplicate MethodInfos are returned by Type.GetMethods() after a token of a generic type's method was loaded.
25 /// </summary>
26 public class MethodFinder
28 private static Hashtable _cachedMethodInfosByType = new Hashtable();
29 private static object _lockObject = new object();
31 public static MethodInfo[] GetAllInstanceMethods(Type type, BindingFlags flags)
33 if ((flags & ~(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)) != 0)
34 throw new ArgumentException("MethodFinder only supports the Public, NonPublic, and Instance binding flags.", "flags");
36 MethodInfo[] methodsInCache;
38 lock(_lockObject)
40 if (!_cachedMethodInfosByType.ContainsKey(type))
42 // We always load all instance methods into the cache, we will filter them later
43 _cachedMethodInfosByType.Add(
44 type,
45 RemoveDuplicates (type.GetMethods(
46 BindingFlags.Public | BindingFlags.NonPublic
47 | BindingFlags.Instance)));
49 methodsInCache = (MethodInfo[]) _cachedMethodInfosByType[type];
51 return MakeFilteredCopy(methodsInCache, flags & (BindingFlags.Public | BindingFlags.NonPublic));
54 private static object RemoveDuplicates (MethodInfo[] infos)
56 Dictionary<MethodInfo, object> uniqueInfos = new Dictionary<MethodInfo, object> (MethodSignatureComparer.Instance);
57 foreach (MethodInfo info in infos)
59 if (!uniqueInfos.ContainsKey (info))
60 uniqueInfos.Add (info, null);
62 MethodInfo[] result = new MethodInfo[uniqueInfos.Count];
63 uniqueInfos.Keys.CopyTo (result, 0);
64 return result;
67 private static MethodInfo[] MakeFilteredCopy(MethodInfo[] methodsInCache, BindingFlags visibilityFlags)
69 if ((visibilityFlags & ~(BindingFlags.Public | BindingFlags.NonPublic)) != 0)
71 throw new ArgumentException("Only supports BindingFlags.Public and NonPublic.", "visibilityFlags");
74 bool includePublic = (visibilityFlags & BindingFlags.Public) == BindingFlags.Public;
75 bool includeNonPublic = (visibilityFlags & BindingFlags.NonPublic) == BindingFlags.NonPublic;
77 // Return a copy of the cached array, only returning the public methods unless requested otherwise
78 List<MethodInfo> result = new List<MethodInfo>(methodsInCache.Length);
80 foreach(MethodInfo method in methodsInCache)
82 if ((method.IsPublic && includePublic) || (!method.IsPublic && includeNonPublic))
84 result.Add(method);
88 return result.ToArray();