// 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.Collections.Generic;
//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;
private static BindingFlags constructorFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.CreateInstance | BindingFlags.NonPublic;
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
}
}