// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. namespace Microsoft.VisualStudio.TestTools.UnitTesting { using System; //using System.Diagnostics; //using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Reflection; /// /// This class represents the live NON public INTERNAL object in the system /// internal class PrivateObject { #region Data // bind everything private const BindingFlags BindToEveryThing = BindingFlags.Default | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public; #pragma warning disable CS0414 // The field 'PrivateObject.constructorFlags' is assigned but its value is never used private static BindingFlags constructorFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.CreateInstance | BindingFlags.NonPublic; #pragma warning restore CS0414 // The field 'PrivateObject.constructorFlags' is assigned but its value is never used private object target; // automatically initialized to null private Type originalType; // automatically initialized to null //private Dictionary> methodCache; // automatically initialized to null #endregion #region Constructors ///// ///// Initializes a new instance of the class that contains ///// the already existing object of the private class ///// ///// object that serves as starting point to reach the private members ///// the derefrencing string using . that points to the object to be retrived as in m_X.m_Y.m_Z //[SuppressMessage("Microsoft.Naming", "CA1720:IdentifiersShouldNotContainTypeNames", MessageId = "obj", Justification = "We don't know anything about the object other than that it's an object, so 'obj' seems reasonable")] //public PrivateObject(object obj, string memberToAccess) //{ // Helper.CheckParameterNotNull(obj, "obj", string.Empty); // ValidateAccessString(memberToAccess); // PrivateObject temp = obj as PrivateObject; // if (temp == null) // { // temp = new PrivateObject(obj); // } // // Split The access string // string[] arr = memberToAccess.Split(new char[] { '.' }); // for (int i = 0; i < arr.Length; i++) // { // object next = temp.InvokeHelper(arr[i], BindToEveryThing | BindingFlags.Instance | BindingFlags.GetField | BindingFlags.GetProperty, null, CultureInfo.InvariantCulture); // temp = new PrivateObject(next); // } // this.target = temp.target; // this.originalType = temp.originalType; //} ///// ///// Initializes a new instance of the class that wraps the ///// specified type. ///// ///// Name of the assembly ///// fully qualified name ///// Argmenets to pass to the constructor //public PrivateObject(string assemblyName, string typeName, params object[] args) // : this(assemblyName, typeName, null, args) //{ //} ///// ///// Initializes a new instance of the class that wraps the ///// specified type. ///// ///// Name of the assembly ///// fully qualified name ///// An array of objects representing the number, order, and type of the parameters for the constructor to get ///// Argmenets to pass to the constructor //public PrivateObject(string assemblyName, string typeName, Type[] parameterTypes, object[] args) // : this(Type.GetType(string.Format(CultureInfo.InvariantCulture, "{0}, {1}", typeName, assemblyName), false), parameterTypes, args) //{ // Helper.CheckParameterNotNull(assemblyName, "assemblyName", string.Empty); // Helper.CheckParameterNotNull(typeName, "typeName", string.Empty); //} ///// ///// Initializes a new instance of the class that wraps the ///// specified type. ///// ///// type of the object to create ///// Argmenets to pass to the constructor //public PrivateObject(Type type, params object[] args) // : this(type, null, args) //{ // Helper.CheckParameterNotNull(type, "type", string.Empty); //} ///// ///// Initializes a new instance of the class that wraps the ///// specified type. ///// ///// type of the object to create ///// An array of objects representing the number, order, and type of the parameters for the constructor to get ///// Argmenets to pass to the constructor //public PrivateObject(Type type, Type[] parameterTypes, object[] args) //{ // Helper.CheckParameterNotNull(type, "type", string.Empty); // object o; // if (parameterTypes != null) // { // ConstructorInfo ci = type.GetConstructor(BindToEveryThing, null, parameterTypes, null); // if (ci == null) // { // throw new ArgumentException(FrameworkMessages.PrivateAccessorConstructorNotFound); // } // try // { // o = ci.Invoke(args); // } // catch (TargetInvocationException e) // { // Debug.Assert(e.InnerException != null, "Inner exception should not be null."); // if (e.InnerException != null) // { // throw e.InnerException; // } // throw; // } // } // else // { // o = Activator.CreateInstance(type, constructorFlags, null, args, null); // } // this.ConstructFrom(o); //} /// /// Initializes a new instance of the class that wraps /// the given object. /// /// object to wrap //[SuppressMessage("Microsoft.Naming", "CA1720:IdentifiersShouldNotContainTypeNames", MessageId = "obj", Justification = "We don't know anything about the object other than that it's an object, so 'obj' seems reasonable")] public PrivateObject(object obj) { Helper.CheckParameterNotNull(obj, "obj", string.Empty); this.ConstructFrom(obj); } /// /// Initializes a new instance of the class that wraps /// the given object. /// /// object to wrap /// PrivateType object //[SuppressMessage("Microsoft.Naming", "CA1720:IdentifiersShouldNotContainTypeNames", MessageId = "obj", Justification = "We don't know anything about the object other than that it's an an object, so 'obj' seems reasonable")] public PrivateObject(object obj, PrivateType type) { Helper.CheckParameterNotNull(type, "type", string.Empty); this.target = obj; this.originalType = type.ReferencedType; } #endregion ///// ///// Gets or sets the target ///// //public object Target //{ // get // { // return this.target; // } // set // { // Helper.CheckParameterNotNull(value, "Target", string.Empty); // this.target = value; // this.originalType = value.GetType(); // } //} ///// ///// Gets the type of underlying object ///// //public Type RealType //{ // get // { // return this.originalType; // } //} //private Dictionary> GenericMethodCache //{ // get // { // if (this.methodCache == null) // { // this.BuildGenericMethodCacheForType(this.originalType); // } // Debug.Assert(this.methodCache != null, "Invalid method cache for type."); // return this.methodCache; // } //} /// /// returns the hash code of the target object /// /// int representing hashcode of the target object public override int GetHashCode() { //Debug.Assert(this.target != null, "target should not be null."); return this.target.GetHashCode(); } /// /// Equals /// /// Object with whom to compare /// returns true if the objects are equal. public override bool Equals(object obj) { if (this != obj) { //Debug.Assert(this.target != null, "target should not be null."); if (typeof(PrivateObject) == obj?.GetType()) { return this.target.Equals(((PrivateObject)obj).target); } else { return false; } } return true; } ///// ///// Invokes the specified method ///// ///// Name of the method ///// Arguments to pass to the member to invoke. ///// Result of method call //public object Invoke(string name, params object[] args) //{ // Helper.CheckParameterNotNull(name, "name", string.Empty); // return this.Invoke(name, null, args, CultureInfo.InvariantCulture); //} ///// ///// Invokes the specified method ///// ///// Name of the method ///// An array of objects representing the number, order, and type of the parameters for the method to get. ///// Arguments to pass to the member to invoke. ///// Result of method call //public object Invoke(string name, Type[] parameterTypes, object[] args) //{ // return this.Invoke(name, parameterTypes, args, CultureInfo.InvariantCulture); //} ///// ///// Invokes the specified method ///// ///// Name of the method ///// An array of objects representing the number, order, and type of the parameters for the method to get. ///// Arguments to pass to the member to invoke. ///// An array of types corresponding to the types of the generic arguments. ///// Result of method call //public object Invoke(string name, Type[] parameterTypes, object[] args, Type[] typeArguments) //{ // return this.Invoke(name, BindToEveryThing, parameterTypes, args, CultureInfo.InvariantCulture, typeArguments); //} ///// ///// Invokes the specified method ///// ///// Name of the method ///// Arguments to pass to the member to invoke. ///// Culture info ///// Result of method call //public object Invoke(string name, object[] args, CultureInfo culture) //{ // return this.Invoke(name, null, args, culture); //} ///// ///// Invokes the specified method ///// ///// Name of the method ///// An array of objects representing the number, order, and type of the parameters for the method to get. ///// Arguments to pass to the member to invoke. ///// Culture info ///// Result of method call //public object Invoke(string name, Type[] parameterTypes, object[] args, CultureInfo culture) //{ // return this.Invoke(name, BindToEveryThing, parameterTypes, args, culture); //} ///// ///// Invokes the specified method ///// ///// Name of the method ///// A bitmask comprised of one or more that specify how the search is conducted. ///// Arguments to pass to the member to invoke. ///// Result of method call //public object Invoke(string name, BindingFlags bindingFlags, params object[] args) //{ // return this.Invoke(name, bindingFlags, null, args, CultureInfo.InvariantCulture); //} ///// ///// Invokes the specified method ///// ///// Name of the method ///// A bitmask comprised of one or more that specify how the search is conducted. ///// An array of objects representing the number, order, and type of the parameters for the method to get. ///// Arguments to pass to the member to invoke. ///// Result of method call //public object Invoke(string name, BindingFlags bindingFlags, Type[] parameterTypes, object[] args) //{ // return this.Invoke(name, bindingFlags, parameterTypes, args, CultureInfo.InvariantCulture); //} ///// ///// Invokes the specified method ///// ///// Name of the method ///// A bitmask comprised of one or more that specify how the search is conducted. ///// Arguments to pass to the member to invoke. ///// Culture info ///// Result of method call //public object Invoke(string name, BindingFlags bindingFlags, object[] args, CultureInfo culture) //{ // return this.Invoke(name, bindingFlags, null, args, culture); //} ///// ///// Invokes the specified method ///// ///// Name of the method ///// A bitmask comprised of one or more that specify how the search is conducted. ///// An array of objects representing the number, order, and type of the parameters for the method to get. ///// Arguments to pass to the member to invoke. ///// Culture info ///// Result of method call //public object Invoke(string name, BindingFlags bindingFlags, Type[] parameterTypes, object[] args, CultureInfo culture) //{ // return this.Invoke(name, bindingFlags, parameterTypes, args, culture, null); //} ///// ///// Invokes the specified method ///// ///// Name of the method ///// A bitmask comprised of one or more that specify how the search is conducted. ///// An array of objects representing the number, order, and type of the parameters for the method to get. ///// Arguments to pass to the member to invoke. ///// Culture info ///// An array of types corresponding to the types of the generic arguments. ///// Result of method call //public object Invoke(string name, BindingFlags bindingFlags, Type[] parameterTypes, object[] args, CultureInfo culture, Type[] typeArguments) //{ // Helper.CheckParameterNotNull(name, "name", string.Empty); // if (parameterTypes != null) // { // bindingFlags |= BindToEveryThing | BindingFlags.Instance; // // Fix up the parameter types // MethodInfo member = this.originalType.GetMethod(name, bindingFlags, null, parameterTypes, null); // // If the method was not found and type arguments were provided for generic paramaters, // // attempt to look up a generic method. // if ((member == null) && (typeArguments != null)) // { // // This method may contain generic parameters...if so, the previous call to // // GetMethod() will fail because it doesn't fully support generic parameters. // // Look in the method cache to see if there is a generic method // // on the incoming type that contains the correct signature. // member = this.GetGenericMethodFromCache(name, parameterTypes, typeArguments, bindingFlags, null); // } // if (member == null) // { // throw new ArgumentException( // string.Format(CultureInfo.CurrentCulture, FrameworkMessages.PrivateAccessorMemberNotFound, name)); // } // try // { // if (member.IsGenericMethodDefinition) // { // MethodInfo constructed = member.MakeGenericMethod(typeArguments); // return constructed.Invoke(this.target, bindingFlags, null, args, culture); // } // else // { // return member.Invoke(this.target, bindingFlags, null, args, culture); // } // } // catch (TargetInvocationException e) // { // Debug.Assert(e.InnerException != null, "Inner exception should not be null."); // if (e.InnerException != null) // { // throw e.InnerException; // } // throw; // } // } // else // { // return this.InvokeHelper(name, bindingFlags | BindingFlags.InvokeMethod, args, culture); // } //} ///// ///// Gets the array element using array of subsrcipts for each dimension ///// ///// Name of the member ///// the indices of array ///// An arrya of elements. //public object GetArrayElement(string name, params int[] indices) //{ // Helper.CheckParameterNotNull(name, "name", string.Empty); // return this.GetArrayElement(name, BindToEveryThing, indices); //} ///// ///// Sets the array element using array of subsrcipts for each dimension ///// ///// Name of the member ///// Value to set ///// the indices of array //public void SetArrayElement(string name, object value, params int[] indices) //{ // Helper.CheckParameterNotNull(name, "name", string.Empty); // this.SetArrayElement(name, BindToEveryThing, value, indices); //} ///// ///// Gets the array element using array of subsrcipts for each dimension ///// ///// Name of the member ///// A bitmask comprised of one or more that specify how the search is conducted. ///// the indices of array ///// An arrya of elements. //public object GetArrayElement(string name, BindingFlags bindingFlags, params int[] indices) //{ // Helper.CheckParameterNotNull(name, "name", string.Empty); // Array arr = (Array)this.InvokeHelper(name, BindingFlags.GetField | bindingFlags, null, CultureInfo.InvariantCulture); // return arr.GetValue(indices); //} ///// ///// Sets the array element using array of subsrcipts for each dimension ///// ///// Name of the member ///// A bitmask comprised of one or more that specify how the search is conducted. ///// Value to set ///// the indices of array //public void SetArrayElement(string name, BindingFlags bindingFlags, object value, params int[] indices) //{ // Helper.CheckParameterNotNull(name, "name", string.Empty); // Array arr = (Array)this.InvokeHelper(name, BindingFlags.GetField | bindingFlags, null, CultureInfo.InvariantCulture); // arr.SetValue(value, indices); //} ///// ///// Get the field ///// ///// Name of the field ///// The field. //public object GetField(string name) //{ // Helper.CheckParameterNotNull(name, "name", string.Empty); // return this.GetField(name, BindToEveryThing); //} ///// ///// Sets the field ///// ///// Name of the field ///// value to set //public void SetField(string name, object value) //{ // Helper.CheckParameterNotNull(name, "name", string.Empty); // this.SetField(name, BindToEveryThing, value); //} ///// ///// Gets the field ///// ///// Name of the field ///// A bitmask comprised of one or more that specify how the search is conducted. ///// The field. //public object GetField(string name, BindingFlags bindingFlags) //{ // Helper.CheckParameterNotNull(name, "name", string.Empty); // return this.InvokeHelper(name, BindingFlags.GetField | bindingFlags, null, CultureInfo.InvariantCulture); //} ///// ///// Sets the field ///// ///// Name of the field ///// A bitmask comprised of one or more that specify how the search is conducted. ///// value to set //public void SetField(string name, BindingFlags bindingFlags, object value) //{ // Helper.CheckParameterNotNull(name, "name", string.Empty); // this.InvokeHelper(name, BindingFlags.SetField | bindingFlags, new object[] { value }, CultureInfo.InvariantCulture); //} /// /// Get the field or property /// /// Name of the field or property /// The field or property. public object GetFieldOrProperty(string name) { Helper.CheckParameterNotNull(name, "name", string.Empty); return this.GetFieldOrProperty(name, BindToEveryThing); } /// /// Sets the field or property /// /// Name of the field or property /// value to set public void SetFieldOrProperty(string name, object value) { Helper.CheckParameterNotNull(name, "name", string.Empty); this.SetFieldOrProperty(name, BindToEveryThing, value); } /// /// Gets the field or property /// /// Name of the field or property /// A bitmask comprised of one or more that specify how the search is conducted. /// The field or property. public object GetFieldOrProperty(string name, BindingFlags bindingFlags) { Helper.CheckParameterNotNull(name, "name", string.Empty); return this.InvokeHelper(name, BindingFlags.GetField | BindingFlags.GetProperty | bindingFlags, null, CultureInfo.InvariantCulture); } /// /// Sets the field or property /// /// Name of the field or property /// A bitmask comprised of one or more that specify how the search is conducted. /// value to set public void SetFieldOrProperty(string name, BindingFlags bindingFlags, object value) { Helper.CheckParameterNotNull(name, "name", string.Empty); this.InvokeHelper(name, BindingFlags.SetField | BindingFlags.SetProperty | bindingFlags, new object[] { value }, CultureInfo.InvariantCulture); } ///// ///// Gets the property ///// ///// Name of the property ///// Arguments to pass to the member to invoke. ///// The property. //public object GetProperty(string name, params object[] args) //{ // return this.GetProperty(name, null, args); //} ///// ///// Gets the property ///// ///// Name of the property ///// An array of objects representing the number, order, and type of the parameters for the indexed property. ///// Arguments to pass to the member to invoke. ///// The property. //public object GetProperty(string name, Type[] parameterTypes, object[] args) //{ // return this.GetProperty(name, BindToEveryThing, parameterTypes, args); //} ///// ///// Set the property ///// ///// Name of the property ///// value to set ///// Arguments to pass to the member to invoke. //public void SetProperty(string name, object value, params object[] args) //{ // this.SetProperty(name, null, value, args); //} ///// ///// Set the property ///// ///// Name of the property ///// An array of objects representing the number, order, and type of the parameters for the indexed property. ///// value to set ///// Arguments to pass to the member to invoke. //public void SetProperty(string name, Type[] parameterTypes, object value, object[] args) //{ // this.SetProperty(name, BindToEveryThing, value, parameterTypes, args); //} ///// ///// Gets the property ///// ///// Name of the property ///// A bitmask comprised of one or more that specify how the search is conducted. ///// Arguments to pass to the member to invoke. ///// The property. //public object GetProperty(string name, BindingFlags bindingFlags, params object[] args) //{ // return this.GetProperty(name, bindingFlags, null, args); //} ///// ///// Gets the property ///// ///// Name of the property ///// A bitmask comprised of one or more that specify how the search is conducted. ///// An array of objects representing the number, order, and type of the parameters for the indexed property. ///// Arguments to pass to the member to invoke. ///// The property. //public object GetProperty(string name, BindingFlags bindingFlags, Type[] parameterTypes, object[] args) //{ // Helper.CheckParameterNotNull(name, "name", string.Empty); // if (parameterTypes != null) // { // PropertyInfo pi = this.originalType.GetProperty(name, bindingFlags, null, null, parameterTypes, null); // if (pi == null) // { // throw new ArgumentException( // string.Format(CultureInfo.CurrentCulture, FrameworkMessages.PrivateAccessorMemberNotFound, name)); // } // return pi.GetValue(this.target, args); // } // else // { // return this.InvokeHelper(name, bindingFlags | BindingFlags.GetProperty, args, null); // } //} ///// ///// Sets the property ///// ///// Name of the property ///// A bitmask comprised of one or more that specify how the search is conducted. ///// value to set ///// Arguments to pass to the member to invoke. //public void SetProperty(string name, BindingFlags bindingFlags, object value, params object[] args) //{ // this.SetProperty(name, bindingFlags, value, null, args); //} ///// ///// Sets the property ///// ///// Name of the property ///// A bitmask comprised of one or more that specify how the search is conducted. ///// value to set ///// An array of objects representing the number, order, and type of the parameters for the indexed property. ///// Arguments to pass to the member to invoke. //public void SetProperty(string name, BindingFlags bindingFlags, object value, Type[] parameterTypes, object[] args) //{ // Helper.CheckParameterNotNull(name, "name", string.Empty); // if (parameterTypes != null) // { // PropertyInfo pi = this.originalType.GetProperty(name, bindingFlags, null, null, parameterTypes, null); // if (pi == null) // { // throw new ArgumentException( // string.Format(CultureInfo.CurrentCulture, FrameworkMessages.PrivateAccessorMemberNotFound, name)); // } // pi.SetValue(this.target, value, args); // } // else // { // object[] pass = new object[(args?.Length ?? 0) + 1]; // pass[0] = value; // args?.CopyTo(pass, 1); // this.InvokeHelper(name, bindingFlags | BindingFlags.SetProperty, pass, null); // } //} #region Private Helpers ///// ///// Validate access string ///// ///// access string //private static void ValidateAccessString(string access) //{ // Helper.CheckParameterNotNull(access, "access", string.Empty); // if (access.Length == 0) // { // throw new ArgumentException(FrameworkMessages.AccessStringInvalidSyntax); // } // string[] arr = access.Split('.'); // foreach (string str in arr) // { // if ((str.Length == 0) || (str.IndexOfAny(new char[] { ' ', '\t', '\n' }) != -1)) // { // throw new ArgumentException(FrameworkMessages.AccessStringInvalidSyntax); // } // } //} /// /// Invokes the memeber /// /// Name of the member /// Additional attributes /// Arguments for the invocation /// Culture /// Result of the invocation private object InvokeHelper(string name, BindingFlags bindingFlags, object[] args, CultureInfo culture) { Helper.CheckParameterNotNull(name, "name", string.Empty); //Debug.Assert(this.target != null, "Internal Error: Null reference is returned for internal object"); // Invoke the actual Method try { return this.originalType.InvokeMember(name, bindingFlags, null, this.target, args, culture); } catch (TargetInvocationException e) { //Debug.Assert(e.InnerException != null, "Inner exception should not be null."); if (e.InnerException != null) { throw e.InnerException; } throw; } } private void ConstructFrom(object obj) { Helper.CheckParameterNotNull(obj, "obj", string.Empty); this.target = obj; this.originalType = obj.GetType(); } //private void BuildGenericMethodCacheForType(Type t) //{ // Debug.Assert(t != null, "type should not be null."); // this.methodCache = new Dictionary>(); // MethodInfo[] members = t.GetMethods(BindToEveryThing); // LinkedList listByName; // automatically initialized to null // foreach (MethodInfo member in members) // { // if (member.IsGenericMethod || member.IsGenericMethodDefinition) // { // if (!this.GenericMethodCache.TryGetValue(member.Name, out listByName)) // { // listByName = new LinkedList(); // this.GenericMethodCache.Add(member.Name, listByName); // } // Debug.Assert(listByName != null, "list should not be null."); // listByName.AddLast(member); // } // } //} ///// ///// Extracts the most appropriate generic method signature from the current private type. ///// ///// The name of the method in which to search the signature cache. ///// An array of types corresponding to the types of the parameters in which to search. ///// An array of types corresponding to the types of the generic arguments. ///// to further filter the method signatures. ///// Modifiers for parameters. ///// A methodinfo instance. //private MethodInfo GetGenericMethodFromCache(string methodName, Type[] parameterTypes, Type[] typeArguments, BindingFlags bindingFlags, ParameterModifier[] modifiers) //{ // Debug.Assert(!string.IsNullOrEmpty(methodName), "Invalid method name."); // Debug.Assert(parameterTypes != null, "Invalid parameter type array."); // Debug.Assert(typeArguments != null, "Invalid type arguments array."); // // Build a preliminary list of method candidates that contain roughly the same signature. // var methodCandidates = this.GetMethodCandidates(methodName, parameterTypes, typeArguments, bindingFlags, modifiers); // // Search of ambiguous methods (methods with the same signature). // MethodInfo[] finalCandidates = new MethodInfo[methodCandidates.Count]; // methodCandidates.CopyTo(finalCandidates, 0); // if ((parameterTypes != null) && (parameterTypes.Length == 0)) // { // for (int i = 0; i < finalCandidates.Length; i++) // { // MethodInfo methodInfo = finalCandidates[i]; // if (!RuntimeTypeHelper.CompareMethodSigAndName(methodInfo, finalCandidates[0])) // { // throw new AmbiguousMatchException(); // } // } // // All the methods have the exact same name and sig so return the most derived one. // return RuntimeTypeHelper.FindMostDerivedNewSlotMeth(finalCandidates, finalCandidates.Length) as MethodInfo; // } // // Now that we have a preliminary list of candidates, select the most appropriate one. // return RuntimeTypeHelper.SelectMethod(bindingFlags, finalCandidates, parameterTypes, modifiers) as MethodInfo; //} //private LinkedList GetMethodCandidates(string methodName, Type[] parameterTypes, Type[] typeArguments, BindingFlags bindingFlags, ParameterModifier[] modifiers) //{ // Debug.Assert(!string.IsNullOrEmpty(methodName), "methodName should not be null."); // Debug.Assert(parameterTypes != null, "parameterTypes should not be null."); // Debug.Assert(typeArguments != null, "typeArguments should not be null."); // LinkedList methodCandidates = new LinkedList(); // LinkedList methods = null; // if (!this.GenericMethodCache.TryGetValue(methodName, out methods)) // { // return methodCandidates; // } // Debug.Assert(methods != null, "methods should not be null."); // foreach (MethodInfo candidate in methods) // { // bool paramMatch = true; // ParameterInfo[] candidateParams = null; // Type[] genericArgs = candidate.GetGenericArguments(); // Type sourceParameterType = null; // if (genericArgs.Length != typeArguments.Length) // { // continue; // } // // Since we can't just get the correct MethodInfo from Reflection, // // we will just match the number of parameters, their order, and their type // var methodCandidate = candidate; // candidateParams = methodCandidate.GetParameters(); // if (candidateParams.Length != parameterTypes.Length) // { // continue; // } // // Exact binding // if ((bindingFlags & BindingFlags.ExactBinding) != 0) // { // int i = 0; // foreach (ParameterInfo candidateParam in candidateParams) // { // sourceParameterType = parameterTypes[i++]; // if (candidateParam.ParameterType.ContainsGenericParameters) // { // // Since we have a generic parameter here, just make sure the IsArray matches. // if (candidateParam.ParameterType.IsArray != sourceParameterType.IsArray) // { // paramMatch = false; // break; // } // } // else // { // if (candidateParam.ParameterType != sourceParameterType) // { // paramMatch = false; // break; // } // } // } // if (paramMatch) // { // methodCandidates.AddLast(methodCandidate); // continue; // } // } // else // { // methodCandidates.AddLast(methodCandidate); // } // } // return methodCandidates; //} #endregion } }