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