Eogene

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

/// <summary>

    /// C#反射新建类实例和调用类方法及属性

    /// </summary>

    public class Reflection

    {

        public static CultureInfo CULTURE_INFO =new CultureInfo("zh-CN",false);

        /// <summary>

        /// 测试是否为空

        /// </summary>

        /// <param name="o">The object to test.</param>

        /// <returns>True if null was passed as argument.</returns>

        public static bool IsNull(object o)

        {

            return (null == o);

        }

        /// <summary>

        /// Casts a certain valueObject into a certain type, by using ChangeType when possible

        /// (i.e. except for exceptions).

        /// </summary>

        /// <param name="valueObject">The object to cast</param>

        /// <param name="typeName">The full name of the type to cast to</param>

        /// <returns>A properly casted object, unless an exception occurs.</returns>

        public static object CastValue(object valueObject, string typeName)

        {

            return CastValue(valueObject, Type.GetType(typeName));

        }

        /// <summary>

        /// Casts a certain valueObject into a certain type, by using ChangeType when possible

        /// </summary>

        /// <param name="valueObject">The object to cast</param>

        /// <param name="type">The type to cast to</param>

        /// <returns>A properly casted object, unless an exception occurs.</returns>

        public static object CastValue(object valueObject, Type type)

        {

            if (type == typeof(System.Exception))

            {

                return new System.Exception((string)valueObject);

            }

            // fix to bug 1474032 provided by Brian Matthews

            else if (type.IsEnum)

            {

                return Enum.Parse(type, valueObject.ToString(), false);

            }

            else

            {

                return Convert.ChangeType(valueObject, type, CULTURE_INFO);

            }

        }

        /// <summary>

        /// Calls a member on an object, either to get or set an attribute or property,

        /// or to invoke a method.

        /// </summary>

        /// <param name="target">The object on which the member will be called.</param>

        /// <param name="name">The name of the member to call.</param>

        /// <param name="argValues">An array of arguments. Use null if no argument is needed.</param>

        /// <returns>The value returned when the member is a method, else null.</returns>

        public static object ObjectCall(object target, string name, object[] argValues)

        {

            return Call(target.GetType(), target, name, argValues);

        }

        /// <summary>

        /// Calls a static member on a class, either to get or set an attribute or property,

        /// or to invoke a method.

        /// </summary>

        /// <param name="type">The fully qualified name of the class to call.</param>

        /// <param name="name">The name of the member to call.</param>

        /// <param name="argValues">An array of arguments. Use null if no argument is needed.</param>

        /// <returns>The value returned when the member is a method, else null.</returns>

        public static object ClassCall(string type, string name, object[] argValues)

        {

            return Call(GetRuntimeType(type), null, name, argValues);

        }

        /// <summary>

        /// Instantiates a new object.

        /// </summary>

        /// <param name="type">The fully qualified name of the class to instantiate.</param>

        /// <param name="argValues">An array of contructor arguments. Use null if no argument is needed.</param>

        /// <returns></returns>

        public static object ClassNew(string type, object[] argValues)

        {

            if (argValues == null) argValues = new object[0];

            Type toInstantiate = GetRuntimeType(type);

            ConstructorInfo ci = toInstantiate.GetConstructor(GetArgumentTypes(argValues));

            if (ci == null)

            {

                throw new TargetException("No matching constructor found on " + type);

            }

            return ci.Invoke(argValues);

        }

        public static object ClassNew(string assembly, string type, object[] argValues)

        {

            if (argValues == null) argValues = new object[0];

            Type toInstantiate = GetRuntimeType(assembly,type);

            ConstructorInfo ci = toInstantiate.GetConstructor(GetArgumentTypes(argValues));

            if (ci == null)

            {

                throw new TargetException("No matching constructor found on " + type);

            }

            return ci.Invoke(argValues);

        }

        // Private methods ------------------------------------------------------------------

        private static object Call(Type type, object target, string name, object[] argValues)

        {

            int nbOfProvidedArgs = 0;

            if (argValues != null) nbOfProvidedArgs = argValues.Length;

            // Check if it is a field name

            FieldInfo fi = type.GetField(name);

            if (fi != null)

            {

                if (nbOfProvidedArgs > 0)

                {

                    if (nbOfProvidedArgs == 1)

                    {

                        fi.SetValue(target, argValues[0]);

                        return null;

                    }

                    else

                    {

                        throw new TargetException(nbOfProvidedArgs + " argument(s) provided for field " + target + "." + name + " when 1 expected");

                    }

                }

                else

                {

                    return fi.GetValue(target);

                }

            }

            // Check if it is a property name

            MethodInfo mi = null;

            PropertyInfo pi;

            if (nbOfProvidedArgs > 0)

            {

                // If we have arguments passed, try to locate a property mathing those

                pi = type.GetProperty(name, GetArgumentTypes(argValues));

                if (pi != null)

                {

                    // If the property is found, give priority to getter

                    // This is of course a limitation, for very specific things 

                    // NxBRE users will enjoy implementing code delegates!

                    mi = pi.GetGetMethod();

                    if (mi == null) mi = pi.GetSetMethod();

                }

                else

                {

                    // If the property is found, try to find a basic non-argument property

                    // and target the set method as we have arguments passed

                    pi = type.GetProperty(name);

                    if (pi != null) mi = pi.GetSetMethod();

                }

            }

            else

            {

                // Having no arguments passed, we clearly want a getter.

                pi = type.GetProperty(name);

                if (pi != null) mi = pi.GetGetMethod();

            }

            // check if it is a method name

            Type[] types = GetArgumentTypes(argValues);

            if (mi == null) mi = type.GetMethod(name, types);

            // the last option is to try to find if there is a single method with the desired name

            if (mi == null)

            {

                try

                {

                    mi = type.GetMethod(name);

                }

                catch (AmbiguousMatchException)

                {

                    // IGNORED

                }

            }

            // if something has been found

            if (mi != null)

            {

                if (argValues == null && mi.GetParameters().Length == 0)

                    return mi.Invoke(target, argValues);

                // if the number of arguments match, perform the invocation

                else if (argValues.Length == mi.GetParameters().Length)

                    return mi.Invoke(target, argValues);

            }

            // nothing found

            return CallMethodWithByRefParametersOrThrow(type,

                                                        target,

                                                        name,

                                                        argValues,

                                                        new TargetException("Can not find member " + type.FullName

                                                                              + "." + name

                                                                              + CollectionHelper.ArrayToString(types)

                                                                              + " for values "

                                                                              + CollectionHelper.ArrayToString(argValues)));

        }

        private static object CallMethodWithByRefParametersOrThrow(Type type, object target, string methodName, object[] args, TargetException te)

        {

            MethodInfo[] mis = type.GetMethods();

            foreach (MethodInfo mi in mis)

            {

                ParameterInfo[] parameters = mi.GetParameters();

                if ((mi.Name.Equals(methodName)) && (parameters.Length == args.Length))

                {

                    bool allMatch = true;

                    IList<int> byRefArgIndices = new List<int>();

                    for (int i = 0; i < parameters.Length; i++)

                    {

                        Type rawParameterType = parameters[i].ParameterType;

                        Type parameterType = rawParameterType.IsByRef ? rawParameterType.GetElementType() : rawParameterType;

                        if (!(parameterType.IsAssignableFrom(args[i].GetType())))

                        {

                            allMatch = false;

                            break;

                        }

                        else if (rawParameterType.IsByRef)

                        {

                            byRefArgIndices.Add(i);

                        }

                    }

                    if (allMatch)

                    {

                        object invocationResult = mi.Invoke(target, args);

                        if (byRefArgIndices.Count == 0)

                        {

                            return invocationResult;

                        }

                        else

                        {

                            object[] result = new object[1 + byRefArgIndices.Count];

                            result[0] = invocationResult;

                            for (int i = 0; i < byRefArgIndices.Count; i++)

                            {

                                result[1 + i] = args[byRefArgIndices[i]];

                            }

                            return result;

                        }

                    }

                }

            }

            throw te;

        }

        private static Assembly GetAssembly(string assemblyName)

        {

            System.Reflection.Assembly assembly = null;

            foreach (System.Reflection.Assembly ase in AppDomain.CurrentDomain.GetAssemblies())

            {

                if (ase.FullName.Trim().Equals(assemblyName.Trim()))

                    assembly = ase;

            }

            return assembly;

        }

        private static Type GetRuntimeType(string type)

        {

            Type runtimeType = Type.GetType(type, true);

            if (runtimeType == null)

            {

                throw new TargetException("Can not find class type " + type);

            }

            else

            {

                return runtimeType;

            }

        }

        public static Type GetRuntimeType(string assemblyName,string type)

        {

            Assembly assembly = GetAssembly(assemblyName);

            if(assembly ==null)

                throw new TargetException("Can not find class type " + type);

            Type runtimeType = assembly.GetType(type, true);

            if (runtimeType == null)

            {

                throw new TargetException("Can not find class type " + type);

            }

            else

            {

                return runtimeType;

            }

        }

        private static Type[] GetArgumentTypes(object[] arguments)

        {

            ArrayList argumentTypes = new ArrayList();

            if(arguments!=null)

            for (int i = 0; i < arguments.Length; i++)

            {

                if (arguments[i] != null)

                {

                    argumentTypes.Add(arguments[i].GetType());

                }

                else

                {

                    argumentTypes.Add(typeof(Object));

                }

            }

            return (Type[])argumentTypes.ToArray(typeof(Type));

        }

    }

/// <summary>

    /// 获取或设置对象属性中字段值

    /// </summary>

    public class Munger

    {

        public Munger()

        {

        }

        public Munger(String aspectName)

        {

            this.AspectName = aspectName;

        }

        /// <summary>

        /// The name of the aspect that is to be peeked or poked.

        /// </summary>

        /// <remarks>

        /// <para>

        /// This name can be a field, property or parameter-less method.

        /// </para>

        /// <para>

        /// The name can be dotted, which chains references. If any link in the chain returns

        /// null, the entire chain is considered to return null.

        /// </para>

        /// </remarks>

        /// <example>"DateOfBirth"</example>

        /// <example>"Owner.HomeAddress.Postcode"</example>

        public string AspectName

        {

            get { return aspectName; }

            set

            {

                aspectName = value;

                if (String.IsNullOrEmpty(aspectName))

                    this.aspectNameParts = new List<string>();

                else

                    this.aspectNameParts = new List<string>(aspectName.Split('.'));

            }

        }

        private string aspectName;

        private List<String> aspectNameParts = new List<string>();

        /// <summary>

        /// Extract the value indicated by our AspectName from the given target.

        /// </summary>

        /// <param name="target">The object that will be peeked</param>

        /// <returns>The value read from the target</returns>

        public Object GetValue(Object target)

        {

            if (this.aspectNameParts.Count == 0)

                return null;

            // TODO: refactor this code with the same code that exists in SetValue()

            const BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance |

                BindingFlags.InvokeMethod | BindingFlags.GetProperty | BindingFlags.GetField;

            const BindingFlags flags2 = BindingFlags.Public | BindingFlags.Instance | BindingFlags.GetProperty;

            foreach (String property in this.aspectNameParts)

            {

                if (target == null)

                    break;

                try

                {

                    target = target.GetType().InvokeMember(property, flags, null, target, null);

                }

                catch (MissingMethodException)

                {

                    // If that didn't work, try to use property as an indexer. This covers things like arrays

                    // dictionaries and DataRows

                    try

                    {

                        target = target.GetType().InvokeMember("Item", flags2, null, target, new Object[] { property });

                    }

                    catch

                    {

                        // We could catch MissingMethodException, KeyNotFoundException, TargetInvocationException plus

                        // others, but basically if anything goes wrong here, we give up

                        return String.Format("'{0}' is not a parameter-less method, property or field of type '{1}'", property, target.GetType());

                    }

                }

            }

            return target;

        }

        /// <summary>

        /// Poke the given value into the given target indicated by our AspectName.

        /// </summary>

        /// <remarks>

        /// <para>

        /// If the AspectName is a dotted path, all the selectors bar the last

        /// are used to find the object that should be updated, and the last

        /// selector is used as the property to update on that object.

        /// </para>

        /// <para>

        /// So, if 'target' is a Person and the AspectName is "HomeAddress.Postcode",

        /// this method will first fetch "HomeAddress" property, and then try to set the

        /// "Postcode" property on the home address object.

        /// </para>

        /// </remarks>

        /// <param name="target">The object that will be poked</param>

        /// <param name="value">The value that will be poked into the target</param>

        public void PutValue(Object target, Object value)

        {

            if (this.aspectNameParts.Count == 0)

                return;

            // Get the object to be poked

            const BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance |

                BindingFlags.InvokeMethod | BindingFlags.GetProperty | BindingFlags.GetField;

            for (int i = 0; i < this.aspectNameParts.Count - 1; i++)

            {

                if (target == null)

                    break;

                try

                {

                    target = target.GetType().InvokeMember(this.aspectNameParts[i], flags, null, target, null);

                }

                catch (System.MissingMethodException)

                {

                    // If that didn't work, try to use property as an indexer. This covers things like arrays

                    // dictionaries and DataRows

                    try

                    {

                        const BindingFlags flags2 = BindingFlags.Public | BindingFlags.Instance | BindingFlags.GetProperty;

                        target = target.GetType().InvokeMember("Item", flags2, null, target, new Object[] { this.aspectNameParts[i] });

                    }

                    catch

                    {

                        // We could catch MissingMethodException, KeyNotFoundException, TargetInvocationException plus

                        // others, but basically if anything goes wrong here, we give up

                        System.Diagnostics.Debug.WriteLine(String.Format("Cannot invoke '{0}' on a {1}", this.aspectNameParts[i], target.GetType()));

                        return;

                    }

                }

            }

            if (target == null)

                return;

            // Now try to set the value

            String lastPart = this.aspectNameParts[this.aspectNameParts.Count - 1];

            try

            {

                // Try to set a property or field first, since that's the most common case

                const BindingFlags flags3 = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance |

                    BindingFlags.SetProperty | BindingFlags.SetField;

                target.GetType().InvokeMember(lastPart, flags3, null, target, new Object[] { value });

            }

            catch (System.MissingMethodException ex)

            {

                try

                {

                    // If that failed, it could be method name that we are looking for

                    const BindingFlags flags4 = BindingFlags.Public | BindingFlags.NonPublic |

                        BindingFlags.Instance | BindingFlags.InvokeMethod;

                    target.GetType().InvokeMember(lastPart, flags4, null, target, new Object[] { value });

                }

                catch (System.MissingMethodException ex2)

                {

                    // If that didn't work, try to use property as an indexer. This covers things like arrays

                    // dictionaries and DataRows

                    try

                    {

                        const BindingFlags flags5 = BindingFlags.Public | BindingFlags.Instance | BindingFlags.SetProperty;

                        target = target.GetType().InvokeMember("Item", flags5, null, target,

                            new Object[] { lastPart, value });

                    }

                    catch

                    {

                        // We could catch MissingMethodException, KeyNotFoundException, TargetInvocationException plus

                        // others, but basically if anything goes wrong here, we give up

                        System.Diagnostics.Debug.WriteLine("Invoke PutAspectByName failed:");

                        System.Diagnostics.Debug.WriteLine(ex);

                        System.Diagnostics.Debug.WriteLine(ex2);

                    }

                }

            }

        }

    }

posted on 2011-10-15 09:46  EoGene  阅读(930)  评论(0编辑  收藏  举报