2014-04-15 22:10:39 +00:00
using System ;
2014-12-20 21:49:53 +00:00
using System.Linq ;
2014-04-15 22:10:39 +00:00
using System.Collections.Generic ;
2014-06-03 02:19:13 +00:00
using System.ComponentModel ;
2014-07-03 18:54:53 +00:00
using System.IO ;
using System.Reflection ;
2014-10-19 23:15:52 +00:00
using System.Reflection.Emit ;
using System.Runtime.InteropServices ;
2014-04-15 22:10:39 +00:00
2014-05-20 15:39:43 +00:00
namespace BizHawk.Common.ReflectionExtensions
2014-04-15 22:10:39 +00:00
{
/// <summary>
/// Reflection based helper methods
/// </summary>
2014-07-03 17:29:01 +00:00
public static class ReflectionExtensions
2014-04-15 22:10:39 +00:00
{
2014-12-20 21:49:53 +00:00
public static IEnumerable < PropertyInfo > GetPropertiesWithAttrib ( this Type type , Type attributeType )
{
return type . GetProperties ( BindingFlags . Public | BindingFlags . Instance | BindingFlags . NonPublic )
. Where ( p = > p . GetCustomAttributes ( attributeType , false ) . Length > 0 ) ;
}
2014-07-03 17:29:01 +00:00
/// <summary>
/// Gets the description attribute from an object
/// </summary>
public static string GetDescription ( this object obj )
{
2014-07-03 18:02:22 +00:00
var type = obj . GetType ( ) ;
2014-07-03 17:29:01 +00:00
var memInfo = type . GetMember ( obj . ToString ( ) ) ;
2014-07-03 18:02:22 +00:00
if ( memInfo . Length > 0 )
2014-07-03 17:29:01 +00:00
{
2014-07-03 18:02:22 +00:00
var attrs = memInfo [ 0 ] . GetCustomAttributes ( typeof ( DescriptionAttribute ) , false ) ;
2014-07-03 17:29:01 +00:00
2014-07-03 18:02:22 +00:00
if ( attrs . Length > 0 )
2014-07-03 17:29:01 +00:00
{
return ( ( DescriptionAttribute ) attrs [ 0 ] ) . Description ;
}
}
return obj . ToString ( ) ;
}
/// <summary>
/// Gets the description attribute from a type
/// </summary>
/// <returns></returns>
2014-06-03 02:19:13 +00:00
public static string Description ( this Type type )
{
var descriptions = ( DescriptionAttribute [ ] )
type . GetCustomAttributes ( typeof ( DescriptionAttribute ) , false ) ;
if ( descriptions . Length = = 0 )
{
return string . Empty ;
}
return descriptions [ 0 ] . Description ;
}
2014-07-03 17:35:49 +00:00
/// <summary>
/// Gets an enum from a description attribute
/// </summary>
/// <typeparam name="T">The type of the enum</typeparam>
/// <param name="description">The description attribute value</param>
/// <returns>An enum value with the given description attribute, if no suitable description is found then a default value of the enum is returned</returns>
/// <remarks>http://stackoverflow.com/questions/4367723/get-enum-from-description-attribute</remarks>
public static T GetEnumFromDescription < T > ( this string description )
{
var type = typeof ( T ) ;
if ( ! type . IsEnum ) throw new InvalidOperationException ( ) ;
foreach ( var field in type . GetFields ( ) )
{
var attribute = Attribute . GetCustomAttribute ( field ,
typeof ( DescriptionAttribute ) ) as DescriptionAttribute ;
if ( attribute ! = null )
{
if ( attribute . Description = = description )
2014-07-03 18:02:22 +00:00
{
2014-07-03 17:35:49 +00:00
return ( T ) field . GetValue ( null ) ;
2014-07-03 18:02:22 +00:00
}
2014-07-03 17:35:49 +00:00
}
else
{
if ( field . Name = = description )
2014-07-03 18:02:22 +00:00
{
2014-07-03 17:35:49 +00:00
return ( T ) field . GetValue ( null ) ;
2014-07-03 18:02:22 +00:00
}
2014-07-03 17:35:49 +00:00
}
}
return default ( T ) ;
}
2014-04-15 22:10:39 +00:00
/// <summary>
/// Takes an object and determines if it has methodName as a public method
/// </summary>
/// <returns>Returns whether or not the obj both contains the method name and the method is public</returns>
2014-05-20 15:39:43 +00:00
public static bool HasExposedMethod ( this object obj , string methodName )
2014-04-15 22:10:39 +00:00
{
var method = obj . GetType ( ) . GetMethod ( methodName ) ;
if ( method ! = null )
{
return method . IsPublic ;
}
return false ;
}
/// <summary>
/// Takes an object and invokes the method
/// The method must exist and be public
/// </summary>
/// <returns>The return value of the method, as an object.
/// If the method returns void, the return value is null
/// If the method does not exist or is not public, it returns null
/// </returns>
2014-05-20 15:39:43 +00:00
public static object InvokeMethod ( this object obj , string methodName , object [ ] args )
2014-04-15 22:10:39 +00:00
{
var method = obj . GetType ( ) . GetMethod ( methodName ) ;
if ( method ! = null & & method . IsPublic )
{
return method . Invoke ( obj , args ) ;
}
return null ;
}
2014-05-20 15:39:43 +00:00
public static bool HasPublicProperty ( this object obj , string propertyName )
{
var property = obj . GetType ( ) . GetProperty ( propertyName ) ;
if ( property ! = null )
{
return property . CanRead ;
}
return false ;
}
public static object GetPropertyValue ( this object obj , string propertyName )
{
var property = obj . GetType ( ) . GetProperty ( propertyName ) ;
if ( property ! = null & & property . CanRead )
{
return property . GetValue ( obj , null ) ;
}
return null ;
}
2014-07-03 17:41:55 +00:00
/// <summary>
/// Takes an enum Type and generates a list of strings from the description attributes
/// </summary>
/// <returns></returns>
public static IEnumerable < string > GetEnumDescriptions ( this Type type )
{
var vals = Enum . GetValues ( type ) ;
foreach ( var v in vals )
{
yield return v . GetDescription ( ) ;
}
}
2014-10-10 18:09:00 +00:00
public static T GetAttribute < T > ( this object o )
{
return ( T ) o . GetType ( ) . GetCustomAttributes ( typeof ( T ) , false ) [ 0 ] ;
}
2014-10-19 23:15:52 +00:00
/// <summary>
/// where the fields begin relative to the address an object references points to
/// </summary>
public static IntPtr ManagedFieldStart { get { return _managedfieldstart ; } }
[StructLayout(LayoutKind.Explicit)]
private class Junkus { [ FieldOffset ( 0 ) ] public IntPtr s ; }
static IntPtr _managedfieldstart = GetManagedOffset ( typeof ( Junkus ) . GetField ( "s" ) ) ;
/// <summary>
/// the address of a field relative to the address an object reference of that type points to. this function is very expensive to call.
/// </summary>
/// <param name="field"></param>
/// <returns></returns>
public static IntPtr GetManagedOffset ( this FieldInfo field )
{
Type type = field . DeclaringType ;
var dyn = new System . Reflection . Emit . DynamicMethod (
"xxz0" , typeof ( IntPtr ) , new Type [ ] { typeof ( object ) } , typeof ( ReflectionExtensions ) . Module , true ) ;
var il = dyn . GetILGenerator ( ) ;
var pin = il . DeclareLocal ( type , true ) ;
var baseaddr = il . DeclareLocal ( typeof ( IntPtr ) ) ;
il . Emit ( OpCodes . Ldarg_0 ) ;
il . Emit ( OpCodes . Stloc , pin ) ; // force cast object to type (invalid), and pin
il . Emit ( OpCodes . Ldloc , pin ) ; // base address of reference (points to typeinfo)
il . Emit ( OpCodes . Conv_I ) ; // convert object ref to intptr (invalid)
il . Emit ( OpCodes . Stloc , baseaddr ) ;
il . Emit ( OpCodes . Ldloc , pin ) ;
il . Emit ( OpCodes . Ldflda , field ) ; // address of desired field
il . Emit ( OpCodes . Conv_I ) ; // convert field& to intptr (invalid)
il . Emit ( OpCodes . Ldloc , baseaddr ) ;
il . Emit ( OpCodes . Sub ) ;
il . Emit ( OpCodes . Ret ) ;
return ( IntPtr ) dyn . Invoke ( null , new object [ ] { new object ( ) } ) ;
}
2014-11-30 14:04:00 +00:00
public static bool ThrowsError ( this MethodInfo info )
{
var il = info . GetMethodBody ( ) . GetILAsByteArray ( ) ;
return ( il [ il . Length - 1 ] = = 0x7A ) ;
}
public static bool IsEmpty ( this MethodInfo info )
{
var il = info . GetMethodBody ( ) . GetILAsByteArray ( ) ;
return ( il . Length = = 1 & & il [ 0 ] = = 0x2A ) ;
}
2014-04-15 22:10:39 +00:00
}
}