1 // Copyright 2004-2008 Castle Project - http://www.castleproject.org/
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
7 // http://www.apache.org/licenses/LICENSE-2.0
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
18 using System
.Collections
;
19 using System
.Collections
.Generic
;
20 using System
.Reflection
;
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.
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
;
40 if (!_cachedMethodInfosByType
.ContainsKey(type
))
42 // We always load all instance methods into the cache, we will filter them later
43 _cachedMethodInfosByType
.Add(
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);
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
))
88 return result
.ToArray();