PageRenderTime 52ms CodeModel.GetById 23ms RepoModel.GetById 1ms app.codeStats 0ms

/src/NUnit/core/Reflect.cs

#
C# | 443 lines | 230 code | 58 blank | 155 comment | 41 complexity | 73c09540fb921d61459f4297955d1eee MD5 | raw file
Possible License(s): GPL-2.0
  1. // ****************************************************************
  2. // This is free software licensed under the NUnit license. You
  3. // may obtain a copy of the license as well as information regarding
  4. // copyright ownership at http://nunit.org.
  5. // ****************************************************************
  6. using System;
  7. using System.Reflection;
  8. using System.Collections;
  9. namespace NUnit.Core
  10. {
  11. /// <summary>
  12. /// Helper methods for inspecting a type by reflection.
  13. ///
  14. /// Many of these methods take ICustomAttributeProvider as an
  15. /// argument to avoid duplication, even though certain attributes can
  16. /// only appear on specific types of members, like MethodInfo or Type.
  17. ///
  18. /// In the case where a type is being examined for the presence of
  19. /// an attribute, interface or named member, the Reflect methods
  20. /// operate with the full name of the member being sought. This
  21. /// removes the necessity of the caller having a reference to the
  22. /// assembly that defines the item being sought and allows the
  23. /// NUnit core to inspect assemblies that reference an older
  24. /// version of the NUnit framework.
  25. /// </summary>
  26. public class Reflect
  27. {
  28. private static readonly BindingFlags AllMembers = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static | BindingFlags.FlattenHierarchy;
  29. #region Attributes
  30. /// <summary>
  31. /// Check presence of attribute of a given type on a member.
  32. /// </summary>
  33. /// <param name="member">The member to examine</param>
  34. /// <param name="attrName">The FullName of the attribute type to look for</param>
  35. /// <param name="inherit">True to include inherited attributes</param>
  36. /// <returns>True if the attribute is present</returns>
  37. public static bool HasAttribute( ICustomAttributeProvider member, string attrName, bool inherit )
  38. {
  39. foreach( Attribute attribute in GetAttributes( member, inherit ) )
  40. if ( IsInstanceOfType( attrName, attribute ) )
  41. return true;
  42. return false;
  43. }
  44. /// <summary>
  45. /// Get attribute of a given type on a member. If multiple attributes
  46. /// of a type are present, the first one found is returned.
  47. /// </summary>
  48. /// <param name="member">The member to examine</param>
  49. /// <param name="attrName">The FullName of the attribute type to look for</param>
  50. /// <param name="inherit">True to include inherited attributes</param>
  51. /// <returns>The attribute or null</returns>
  52. public static System.Attribute GetAttribute(ICustomAttributeProvider member, string attrName, bool inherit)
  53. {
  54. foreach (Attribute attribute in GetAttributes( member, inherit ) )
  55. if ( IsInstanceOfType( attrName, attribute ) )
  56. return attribute;
  57. return null;
  58. }
  59. /// <summary>
  60. /// Get all attributes of a given type on a member.
  61. /// </summary>
  62. /// <param name="member">The member to examine</param>
  63. /// <param name="attrName">The FullName of the attribute type to look for</param>
  64. /// <param name="inherit">True to include inherited attributes</param>
  65. /// <returns>The attribute or null</returns>
  66. public static System.Attribute[] GetAttributes(
  67. ICustomAttributeProvider member, string attrName, bool inherit)
  68. {
  69. ArrayList result = new ArrayList();
  70. foreach( Attribute attribute in GetAttributes( member, inherit ) )
  71. if ( IsInstanceOfType( attrName, attribute ) )
  72. result.Add( attribute );
  73. return (System.Attribute[])result.ToArray( typeof( System.Attribute ) );
  74. }
  75. /// <summary>
  76. /// Get all attributes on a member.
  77. /// </summary>
  78. /// <param name="member">The member to examine</param>
  79. /// <param name="inherit">True to include inherited attributes</param>
  80. /// <returns>The attribute or null</returns>
  81. public static System.Attribute[] GetAttributes(
  82. ICustomAttributeProvider member, bool inherit)
  83. {
  84. object[] attributes = member.GetCustomAttributes(inherit);
  85. System.Attribute[] result = new System.Attribute[attributes.Length];
  86. int n = 0;
  87. foreach (Attribute attribute in attributes)
  88. result[n++] = attribute;
  89. return result;
  90. }
  91. #endregion
  92. #region Interfaces
  93. /// <summary>
  94. /// Check to see if a type implements a named interface.
  95. /// </summary>
  96. /// <param name="fixtureType">The type to examine</param>
  97. /// <param name="interfaceName">The FullName of the interface to check for</param>
  98. /// <returns>True if the interface is implemented by the type</returns>
  99. public static bool HasInterface( Type fixtureType, string interfaceName )
  100. {
  101. foreach( Type type in fixtureType.GetInterfaces() )
  102. if ( type.FullName == interfaceName )
  103. return true;
  104. return false;
  105. }
  106. #endregion
  107. #region Inheritance
  108. //SHMARYA: [ 10/12/2005 ]
  109. /// <summary>
  110. /// Checks to see if a type inherits from a named type.
  111. /// </summary>
  112. /// <param name="type">The type to examine</param>
  113. /// <param name="parentType">The FullName of the inherited type to look for</param>
  114. /// <returns>True if the type inherits from the named type.</returns>
  115. public static bool InheritsFrom( Type type, string typeName )
  116. {
  117. for( Type current = type; current != typeof( object ); current = current.BaseType )
  118. if( current.FullName == typeName )
  119. return true;
  120. return false;
  121. }
  122. public static bool InheritsFrom( object obj, string typeName )
  123. {
  124. return InheritsFrom( obj.GetType(), typeName );
  125. }
  126. public static bool IsInstanceOfType( string typeName, Attribute attr )
  127. {
  128. Type type = attr.GetType();
  129. return type.FullName == typeName || InheritsFrom( type, typeName );
  130. }
  131. #endregion
  132. #region Get Methods of a type
  133. /// <summary>
  134. /// Find the default constructor on a type
  135. /// </summary>
  136. /// <param name="fixtureType"></param>
  137. /// <returns></returns>
  138. public static ConstructorInfo GetConstructor( Type fixtureType )
  139. {
  140. return fixtureType.GetConstructor( Type.EmptyTypes );
  141. }
  142. /// <summary>
  143. /// Examine a fixture type and return an array of methods having a
  144. /// particular attribute. The array is order with base methods first.
  145. /// </summary>
  146. /// <param name="fixtureType">The type to examine</param>
  147. /// <param name="attributeName">The FullName of the attribute to look for</param>
  148. /// <returns>The array of methods found</returns>
  149. public static MethodInfo[] GetMethodsWithAttribute(Type fixtureType, string attributeName, bool inherit)
  150. {
  151. ArrayList list = new ArrayList();
  152. foreach (MethodInfo method in GetMethods(fixtureType))
  153. {
  154. if (HasAttribute(method, attributeName, inherit))
  155. list.Add(method);
  156. }
  157. list.Sort(new BaseTypesFirstComparer());
  158. return (MethodInfo[])list.ToArray(typeof(MethodInfo));
  159. }
  160. private static MethodInfo[] GetMethods(Type fixtureType)
  161. {
  162. MethodInfo[] result = fixtureType.GetMethods(AllMembers);
  163. return result;
  164. }
  165. private class BaseTypesFirstComparer : IComparer
  166. {
  167. #region IComparer Members
  168. public int Compare(object x, object y)
  169. {
  170. MethodInfo m1 = x as MethodInfo;
  171. MethodInfo m2 = y as MethodInfo;
  172. if (m1 == null || m2 == null) return 0;
  173. Type m1Type = m1.DeclaringType;
  174. Type m2Type = m2.DeclaringType;
  175. if ( m1Type == m2Type ) return 0;
  176. if ( m1Type.IsAssignableFrom(m2Type) ) return -1;
  177. return 1;
  178. }
  179. #endregion
  180. }
  181. /// <summary>
  182. /// Examine a fixture type and return true if it has a method with
  183. /// a particular attribute.
  184. /// </summary>
  185. /// <param name="fixtureType">The type to examine</param>
  186. /// <param name="attributeName">The FullName of the attribute to look for</param>
  187. /// <returns>True if found, otherwise false</returns>
  188. public static bool HasMethodWithAttribute(Type fixtureType, string attributeName, bool inherit)
  189. {
  190. foreach (MethodInfo method in GetMethods( fixtureType ))
  191. {
  192. if (HasAttribute(method, attributeName, inherit))
  193. return true;
  194. }
  195. return false;
  196. }
  197. /// <summary>
  198. /// Examine a fixture type and get a method with a particular name.
  199. /// In the case of overloads, the first one found is returned.
  200. /// </summary>
  201. /// <param name="fixtureType">The type to examine</param>
  202. /// <param name="methodName">The name of the method</param>
  203. /// <returns>A MethodInfo or null</returns>
  204. public static MethodInfo GetNamedMethod(Type fixtureType, string methodName)
  205. {
  206. foreach (MethodInfo method in GetMethods( fixtureType ))
  207. {
  208. if (method.Name == methodName)
  209. return method;
  210. }
  211. return null;
  212. }
  213. /// <summary>
  214. /// Examine a fixture type and get a method with a particular name and list
  215. /// of arguments. In the case of overloads, the first one found is returned.
  216. /// </summary>
  217. /// <param name="fixtureType">The type to examine</param>
  218. /// <param name="methodName">The name of the method</param>
  219. /// <param name="argTypes">The full names of the argument types to search for</param>
  220. /// <returns>A MethodInfo or null</returns>
  221. public static MethodInfo GetNamedMethod(Type fixtureType, string methodName,
  222. string[] argTypes)
  223. {
  224. foreach (MethodInfo method in GetMethods(fixtureType) )
  225. {
  226. if (method.Name == methodName)
  227. {
  228. ParameterInfo[] parameters = method.GetParameters();
  229. if (parameters.Length == argTypes.Length)
  230. {
  231. bool match = true;
  232. for (int i = 0; i < argTypes.Length; i++)
  233. if (parameters[i].ParameterType.FullName != argTypes[i])
  234. {
  235. match = false;
  236. break;
  237. }
  238. if (match)
  239. return method;
  240. }
  241. }
  242. }
  243. return null;
  244. }
  245. #endregion
  246. #region Get Properties of a type
  247. /// <summary>
  248. /// Examine a type and return a property having a particular attribute.
  249. /// In the case of multiple methods, the first one found is returned.
  250. /// </summary>
  251. /// <param name="fixtureType">The type to examine</param>
  252. /// <param name="attributeName">The FullName of the attribute to look for</param>
  253. /// <returns>A PropertyInfo or null</returns>
  254. public static PropertyInfo GetPropertyWithAttribute( Type fixtureType, string attributeName )
  255. {
  256. foreach(PropertyInfo property in fixtureType.GetProperties( AllMembers ) )
  257. {
  258. if( HasAttribute( property, attributeName, true ) )
  259. return property;
  260. }
  261. return null;
  262. }
  263. /// <summary>
  264. /// Examine a type and get a property with a particular name.
  265. /// In the case of overloads, the first one found is returned.
  266. /// </summary>
  267. /// <param name="type">The type to examine</param>
  268. /// <param name="bindingFlags">BindingFlags to use</param>
  269. /// <returns>A PropertyInfo or null</returns>
  270. public static PropertyInfo GetNamedProperty( Type type, string name, BindingFlags bindingFlags )
  271. {
  272. return type.GetProperty( name, bindingFlags );
  273. }
  274. /// <summary>
  275. /// Get the value of a named property on an object using binding flags of Public and Instance
  276. /// </summary>
  277. /// <param name="obj">The object for which the property value is needed</param>
  278. /// <param name="name">The name of a non-indexed property of the object</param>
  279. /// <returns></returns>
  280. public static object GetPropertyValue( object obj, string name )
  281. {
  282. return GetPropertyValue( obj, name, BindingFlags.Public | BindingFlags.Instance );
  283. }
  284. /// <summary>
  285. /// Get the value of a named property on an object
  286. /// </summary>
  287. /// <param name="obj">The object for which the property value is needed</param>
  288. /// <param name="name">The name of a non-indexed property of the object</param>
  289. /// <param name="bindingFlags">BindingFlags for use in determining which properties are needed</param>param>
  290. /// <returns></returns>
  291. public static object GetPropertyValue( object obj, string name, BindingFlags bindingFlags )
  292. {
  293. PropertyInfo property = GetNamedProperty( obj.GetType(), name, bindingFlags );
  294. if ( property != null )
  295. return property.GetValue( obj, null );
  296. return null;
  297. }
  298. #endregion
  299. #region Invoke Methods
  300. /// <summary>
  301. /// Invoke the default constructor on a Type
  302. /// </summary>
  303. /// <param name="type">The Type to be constructed</param>
  304. /// <returns>An instance of the Type</returns>
  305. public static object Construct(Type type)
  306. {
  307. ConstructorInfo ctor = GetConstructor(type);
  308. if (ctor == null)
  309. throw new InvalidTestFixtureException(type.FullName + " does not have a default constructor");
  310. return ctor.Invoke(null);
  311. }
  312. /// <summary>
  313. /// Invoke a constructor on a Type with arguments
  314. /// </summary>
  315. /// <param name="type">The Type to be constructed</param>
  316. /// <param name="arguments">Arguments to the constructor</param>
  317. /// <returns>An instance of the Type</returns>
  318. public static object Construct(Type type, object[] arguments)
  319. {
  320. if (arguments == null) return Construct(type);
  321. //Type[] argTypes = GetTypeArray(arguments);
  322. //ConstructorInfo ctor = GetConstructor(type, argTypes);
  323. //if (ctor == null)
  324. // throw new InvalidTestFixtureException(type.FullName + " does not have a suitable constructor");
  325. try
  326. {
  327. return type.InvokeMember(type.Name, BindingFlags.CreateInstance, null, null, arguments);
  328. }
  329. catch (Exception ex)
  330. {
  331. throw new InvalidTestFixtureException(type.FullName + " does not have a suitable constructor", ex);
  332. }
  333. }
  334. /// <summary>
  335. /// Returns an array of types from an array of objects.
  336. /// Used because the compact framework doesn't support
  337. /// Type.GetTypeArray()
  338. /// </summary>
  339. /// <param name="objects">An array of objects</param>
  340. /// <returns>An array of Types</returns>
  341. public static Type[] GetTypeArray(object[] objects)
  342. {
  343. Type[] types = new Type[objects.Length];
  344. int index = 0;
  345. foreach (object o in objects)
  346. types[index++] = o == null ? null : o.GetType();
  347. return types;
  348. }
  349. /// <summary>
  350. /// Invoke a parameterless method returning void on an object.
  351. /// </summary>
  352. /// <param name="method">A MethodInfo for the method to be invoked</param>
  353. /// <param name="fixture">The object on which to invoke the method</param>
  354. public static object InvokeMethod( MethodInfo method, object fixture )
  355. {
  356. return InvokeMethod( method, fixture, null );
  357. }
  358. /// <summary>
  359. /// Invoke a method returning void, converting any TargetInvocationException
  360. /// to an NUnitException
  361. /// </summary>
  362. /// <param name="method">A MethodInfo for the method to be invoked</param>
  363. /// <param name="fixture">The object on which to invoke the method</param>
  364. public static object InvokeMethod( MethodInfo method, object fixture, params object[] args )
  365. {
  366. if(method != null)
  367. {
  368. try
  369. {
  370. return method.Invoke( fixture, args );
  371. }
  372. catch(TargetInvocationException e)
  373. {
  374. Exception inner = e.InnerException;
  375. throw new NUnitException("Rethrown",inner);
  376. }
  377. }
  378. return null;
  379. }
  380. #endregion
  381. #region Private Constructor for static-only class
  382. private Reflect() { }
  383. #endregion
  384. }
  385. }