mirror of
https://github.com/Kareadita/Kavita.git
synced 2025-05-31 04:04:19 -04:00
1864 lines
79 KiB
C#
1864 lines
79 KiB
C#
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
|
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Diagnostics;
|
|
using System.Globalization;
|
|
using System.Reflection;
|
|
|
|
namespace Microsoft.VisualStudio.TestTools.UnitTesting
|
|
{
|
|
/// <summary>
|
|
/// This class represents the live NON public INTERNAL object in the system
|
|
/// </summary>
|
|
public class PrivateObject
|
|
{
|
|
// 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<string, LinkedList<MethodInfo>> methodCache; // automatically initialized to null
|
|
|
|
/// <summary>
|
|
/// Initializes a new instance of the <see cref="PrivateObject"/> class that contains
|
|
/// the already existing object of the private class
|
|
/// </summary>
|
|
/// <param name="obj"> object that serves as starting point to reach the private members</param>
|
|
/// <param name="memberToAccess">the derefrencing string using . that points to the object to be retrived as in m_X.m_Y.m_Z</param>
|
|
public PrivateObject(object obj, string memberToAccess)
|
|
{
|
|
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;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Initializes a new instance of the <see cref="PrivateObject"/> class that wraps the
|
|
/// specified type.
|
|
/// </summary>
|
|
/// <param name="assemblyName">Name of the assembly</param>
|
|
/// <param name="typeName">fully qualified name</param>
|
|
/// <param name="args">Argmenets to pass to the constructor</param>
|
|
public PrivateObject(string assemblyName, string typeName, params object[] args)
|
|
: this(assemblyName, typeName, null, args)
|
|
{
|
|
}
|
|
|
|
/// <summary>
|
|
/// Initializes a new instance of the <see cref="PrivateObject"/> class that wraps the
|
|
/// specified type.
|
|
/// </summary>
|
|
/// <param name="assemblyName">Name of the assembly</param>
|
|
/// <param name="typeName">fully qualified name</param>
|
|
/// <param name="parameterTypes">An array of <see cref="T:System.Type"/> objects representing the number, order, and type of the parameters for the constructor to get</param>
|
|
/// <param name="args">Argmenets to pass to the constructor</param>
|
|
public PrivateObject(string assemblyName, string typeName, Type[] parameterTypes, object[] args)
|
|
: this(Type.GetType(string.Format(CultureInfo.InvariantCulture, "{0}, {1}", typeName, assemblyName), false), parameterTypes, args)
|
|
{
|
|
}
|
|
|
|
/// <summary>
|
|
/// Initializes a new instance of the <see cref="PrivateObject"/> class that wraps the
|
|
/// specified type.
|
|
/// </summary>
|
|
/// <param name="type">type of the object to create</param>
|
|
/// <param name="args">Argmenets to pass to the constructor</param>
|
|
public PrivateObject(Type type, params object[] args)
|
|
: this(type, null, args)
|
|
{
|
|
}
|
|
|
|
/// <summary>
|
|
/// Initializes a new instance of the <see cref="PrivateObject"/> class that wraps the
|
|
/// specified type.
|
|
/// </summary>
|
|
/// <param name="type">type of the object to create</param>
|
|
/// <param name="parameterTypes">An array of <see cref="T:System.Type"/> objects representing the number, order, and type of the parameters for the constructor to get</param>
|
|
/// <param name="args">Argmenets to pass to the constructor</param>
|
|
public PrivateObject(Type type, Type[] parameterTypes, object[] args)
|
|
{
|
|
object o;
|
|
if (parameterTypes != null)
|
|
{
|
|
ConstructorInfo ci = type.GetConstructor(BindToEveryThing, null, parameterTypes, null);
|
|
if (ci == null)
|
|
{
|
|
throw new ArgumentException("The constructor with the specified signature could not be found. You might need to regenerate your private accessor, or the member may be private and defined on a base class. If the latter is true, you need to pass the type that defines the member into PrivateObject's constructor.");
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Initializes a new instance of the <see cref="PrivateObject"/> class that wraps
|
|
/// the given object.
|
|
/// </summary>
|
|
/// <param name="obj">object to wrap</param>
|
|
public PrivateObject(object obj)
|
|
{
|
|
this.ConstructFrom(obj);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Initializes a new instance of the <see cref="PrivateObject"/> class that wraps
|
|
/// the given object.
|
|
/// </summary>
|
|
/// <param name="obj">object to wrap</param>
|
|
/// <param name="type">PrivateType object</param>
|
|
public PrivateObject(object obj, PrivateType type)
|
|
{
|
|
this.target = obj;
|
|
this.originalType = type.ReferencedType;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets or sets the target
|
|
/// </summary>
|
|
public object Target
|
|
{
|
|
get
|
|
{
|
|
return this.target;
|
|
}
|
|
|
|
set
|
|
{
|
|
this.target = value;
|
|
this.originalType = value.GetType();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the type of underlying object
|
|
/// </summary>
|
|
public Type RealType
|
|
{
|
|
get
|
|
{
|
|
return this.originalType;
|
|
}
|
|
}
|
|
|
|
private Dictionary<string, LinkedList<MethodInfo>> GenericMethodCache
|
|
{
|
|
get
|
|
{
|
|
if (this.methodCache == null)
|
|
{
|
|
this.BuildGenericMethodCacheForType(this.originalType);
|
|
}
|
|
|
|
Debug.Assert(this.methodCache != null, "Invalid method cache for type.");
|
|
|
|
return this.methodCache;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// returns the hash code of the target object
|
|
/// </summary>
|
|
/// <returns>int representing hashcode of the target object</returns>
|
|
public override int GetHashCode()
|
|
{
|
|
Debug.Assert(this.target != null, "target should not be null.");
|
|
return this.target.GetHashCode();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Equals
|
|
/// </summary>
|
|
/// <param name="obj">Object with whom to compare</param>
|
|
/// <returns>returns true if the objects are equal.</returns>
|
|
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;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Invokes the specified method
|
|
/// </summary>
|
|
/// <param name="name">Name of the method</param>
|
|
/// <param name="args">Arguments to pass to the member to invoke.</param>
|
|
/// <returns>Result of method call</returns>
|
|
public object Invoke(string name, params object[] args)
|
|
{
|
|
return this.Invoke(name, null, args, CultureInfo.InvariantCulture);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Invokes the specified method
|
|
/// </summary>
|
|
/// <param name="name">Name of the method</param>
|
|
/// <param name="parameterTypes">An array of <see cref="T:System.Type"/> objects representing the number, order, and type of the parameters for the method to get.</param>
|
|
/// <param name="args">Arguments to pass to the member to invoke.</param>
|
|
/// <returns>Result of method call</returns>
|
|
public object Invoke(string name, Type[] parameterTypes, object[] args)
|
|
{
|
|
return this.Invoke(name, parameterTypes, args, CultureInfo.InvariantCulture);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Invokes the specified method
|
|
/// </summary>
|
|
/// <param name="name">Name of the method</param>
|
|
/// <param name="parameterTypes">An array of <see cref="T:System.Type"/> objects representing the number, order, and type of the parameters for the method to get.</param>
|
|
/// <param name="args">Arguments to pass to the member to invoke.</param>
|
|
/// <param name="typeArguments">An array of types corresponding to the types of the generic arguments.</param>
|
|
/// <returns>Result of method call</returns>
|
|
public object Invoke(string name, Type[] parameterTypes, object[] args, Type[] typeArguments)
|
|
{
|
|
return this.Invoke(name, BindToEveryThing, parameterTypes, args, CultureInfo.InvariantCulture, typeArguments);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Invokes the specified method
|
|
/// </summary>
|
|
/// <param name="name">Name of the method</param>
|
|
/// <param name="args">Arguments to pass to the member to invoke.</param>
|
|
/// <param name="culture">Culture info</param>
|
|
/// <returns>Result of method call</returns>
|
|
public object Invoke(string name, object[] args, CultureInfo culture)
|
|
{
|
|
return this.Invoke(name, null, args, culture);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Invokes the specified method
|
|
/// </summary>
|
|
/// <param name="name">Name of the method</param>
|
|
/// <param name="parameterTypes">An array of <see cref="T:System.Type"/> objects representing the number, order, and type of the parameters for the method to get.</param>
|
|
/// <param name="args">Arguments to pass to the member to invoke.</param>
|
|
/// <param name="culture">Culture info</param>
|
|
/// <returns>Result of method call</returns>
|
|
public object Invoke(string name, Type[] parameterTypes, object[] args, CultureInfo culture)
|
|
{
|
|
return this.Invoke(name, BindToEveryThing, parameterTypes, args, culture);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Invokes the specified method
|
|
/// </summary>
|
|
/// <param name="name">Name of the method</param>
|
|
/// <param name="bindingFlags">A bitmask comprised of one or more <see cref="T:System.Reflection.BindingFlags"/> that specify how the search is conducted.</param>
|
|
/// <param name="args">Arguments to pass to the member to invoke.</param>
|
|
/// <returns>Result of method call</returns>
|
|
public object Invoke(string name, BindingFlags bindingFlags, params object[] args)
|
|
{
|
|
return this.Invoke(name, bindingFlags, null, args, CultureInfo.InvariantCulture);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Invokes the specified method
|
|
/// </summary>
|
|
/// <param name="name">Name of the method</param>
|
|
/// <param name="bindingFlags">A bitmask comprised of one or more <see cref="T:System.Reflection.BindingFlags"/> that specify how the search is conducted.</param>
|
|
/// <param name="parameterTypes">An array of <see cref="T:System.Type"/> objects representing the number, order, and type of the parameters for the method to get.</param>
|
|
/// <param name="args">Arguments to pass to the member to invoke.</param>
|
|
/// <returns>Result of method call</returns>
|
|
public object Invoke(string name, BindingFlags bindingFlags, Type[] parameterTypes, object[] args)
|
|
{
|
|
return this.Invoke(name, bindingFlags, parameterTypes, args, CultureInfo.InvariantCulture);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Invokes the specified method
|
|
/// </summary>
|
|
/// <param name="name">Name of the method</param>
|
|
/// <param name="bindingFlags">A bitmask comprised of one or more <see cref="T:System.Reflection.BindingFlags"/> that specify how the search is conducted.</param>
|
|
/// <param name="args">Arguments to pass to the member to invoke.</param>
|
|
/// <param name="culture">Culture info</param>
|
|
/// <returns>Result of method call</returns>
|
|
public object Invoke(string name, BindingFlags bindingFlags, object[] args, CultureInfo culture)
|
|
{
|
|
return this.Invoke(name, bindingFlags, null, args, culture);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Invokes the specified method
|
|
/// </summary>
|
|
/// <param name="name">Name of the method</param>
|
|
/// <param name="bindingFlags">A bitmask comprised of one or more <see cref="T:System.Reflection.BindingFlags"/> that specify how the search is conducted.</param>
|
|
/// <param name="parameterTypes">An array of <see cref="T:System.Type"/> objects representing the number, order, and type of the parameters for the method to get.</param>
|
|
/// <param name="args">Arguments to pass to the member to invoke.</param>
|
|
/// <param name="culture">Culture info</param>
|
|
/// <returns>Result of method call</returns>
|
|
public object Invoke(string name, BindingFlags bindingFlags, Type[] parameterTypes, object[] args, CultureInfo culture)
|
|
{
|
|
return this.Invoke(name, bindingFlags, parameterTypes, args, culture, null);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Invokes the specified method
|
|
/// </summary>
|
|
/// <param name="name">Name of the method</param>
|
|
/// <param name="bindingFlags">A bitmask comprised of one or more <see cref="T:System.Reflection.BindingFlags"/> that specify how the search is conducted.</param>
|
|
/// <param name="parameterTypes">An array of <see cref="T:System.Type"/> objects representing the number, order, and type of the parameters for the method to get.</param>
|
|
/// <param name="args">Arguments to pass to the member to invoke.</param>
|
|
/// <param name="culture">Culture info</param>
|
|
/// <param name="typeArguments">An array of types corresponding to the types of the generic arguments.</param>
|
|
/// <returns>Result of method call</returns>
|
|
public object Invoke(string name, BindingFlags bindingFlags, Type[] parameterTypes, object[] args, CultureInfo culture, Type[] typeArguments)
|
|
{
|
|
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, "The member specified ({0}) could not be found. You might need to regenerate your private accessor, or the member may be private and defined on a base class. If the latter is true, you need to pass the type that defines the member into PrivateObject's constructor.", 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);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the array element using array of subsrcipts for each dimension
|
|
/// </summary>
|
|
/// <param name="name">Name of the member</param>
|
|
/// <param name="indices">the indices of array</param>
|
|
/// <returns>An arrya of elements.</returns>
|
|
public object GetArrayElement(string name, params int[] indices)
|
|
{
|
|
return this.GetArrayElement(name, BindToEveryThing, indices);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Sets the array element using array of subsrcipts for each dimension
|
|
/// </summary>
|
|
/// <param name="name">Name of the member</param>
|
|
/// <param name="value">Value to set</param>
|
|
/// <param name="indices">the indices of array</param>
|
|
public void SetArrayElement(string name, object value, params int[] indices)
|
|
{
|
|
this.SetArrayElement(name, BindToEveryThing, value, indices);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the array element using array of subsrcipts for each dimension
|
|
/// </summary>
|
|
/// <param name="name">Name of the member</param>
|
|
/// <param name="bindingFlags">A bitmask comprised of one or more <see cref="T:System.Reflection.BindingFlags"/> that specify how the search is conducted.</param>
|
|
/// <param name="indices">the indices of array</param>
|
|
/// <returns>An arrya of elements.</returns>
|
|
public object GetArrayElement(string name, BindingFlags bindingFlags, params int[] indices)
|
|
{
|
|
Array arr = (Array)this.InvokeHelper(name, BindingFlags.GetField | bindingFlags, null, CultureInfo.InvariantCulture);
|
|
return arr.GetValue(indices);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Sets the array element using array of subsrcipts for each dimension
|
|
/// </summary>
|
|
/// <param name="name">Name of the member</param>
|
|
/// <param name="bindingFlags">A bitmask comprised of one or more <see cref="T:System.Reflection.BindingFlags"/> that specify how the search is conducted.</param>
|
|
/// <param name="value">Value to set</param>
|
|
/// <param name="indices">the indices of array</param>
|
|
public void SetArrayElement(string name, BindingFlags bindingFlags, object value, params int[] indices)
|
|
{
|
|
Array arr = (Array)this.InvokeHelper(name, BindingFlags.GetField | bindingFlags, null, CultureInfo.InvariantCulture);
|
|
arr.SetValue(value, indices);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get the field
|
|
/// </summary>
|
|
/// <param name="name">Name of the field</param>
|
|
/// <returns>The field.</returns>
|
|
public object GetField(string name)
|
|
{
|
|
return this.GetField(name, BindToEveryThing);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Sets the field
|
|
/// </summary>
|
|
/// <param name="name">Name of the field</param>
|
|
/// <param name="value">value to set</param>
|
|
public void SetField(string name, object value)
|
|
{
|
|
this.SetField(name, BindToEveryThing, value);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the field
|
|
/// </summary>
|
|
/// <param name="name">Name of the field</param>
|
|
/// <param name="bindingFlags">A bitmask comprised of one or more <see cref="T:System.Reflection.BindingFlags"/> that specify how the search is conducted.</param>
|
|
/// <returns>The field.</returns>
|
|
public object GetField(string name, BindingFlags bindingFlags)
|
|
{
|
|
return this.InvokeHelper(name, BindingFlags.GetField | bindingFlags, null, CultureInfo.InvariantCulture);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Sets the field
|
|
/// </summary>
|
|
/// <param name="name">Name of the field</param>
|
|
/// <param name="bindingFlags">A bitmask comprised of one or more <see cref="T:System.Reflection.BindingFlags"/> that specify how the search is conducted.</param>
|
|
/// <param name="value">value to set</param>
|
|
public void SetField(string name, BindingFlags bindingFlags, object value)
|
|
{
|
|
this.InvokeHelper(name, BindingFlags.SetField | bindingFlags, new object[] { value }, CultureInfo.InvariantCulture);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get the field or property
|
|
/// </summary>
|
|
/// <param name="name">Name of the field or property</param>
|
|
/// <returns>The field or property.</returns>
|
|
public object GetFieldOrProperty(string name)
|
|
{
|
|
return this.GetFieldOrProperty(name, BindToEveryThing);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Sets the field or property
|
|
/// </summary>
|
|
/// <param name="name">Name of the field or property</param>
|
|
/// <param name="value">value to set</param>
|
|
public void SetFieldOrProperty(string name, object value)
|
|
{
|
|
this.SetFieldOrProperty(name, BindToEveryThing, value);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the field or property
|
|
/// </summary>
|
|
/// <param name="name">Name of the field or property</param>
|
|
/// <param name="bindingFlags">A bitmask comprised of one or more <see cref="T:System.Reflection.BindingFlags"/> that specify how the search is conducted.</param>
|
|
/// <returns>The field or property.</returns>
|
|
public object GetFieldOrProperty(string name, BindingFlags bindingFlags)
|
|
{
|
|
return this.InvokeHelper(name, BindingFlags.GetField | BindingFlags.GetProperty | bindingFlags, null, CultureInfo.InvariantCulture);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Sets the field or property
|
|
/// </summary>
|
|
/// <param name="name">Name of the field or property</param>
|
|
/// <param name="bindingFlags">A bitmask comprised of one or more <see cref="T:System.Reflection.BindingFlags"/> that specify how the search is conducted.</param>
|
|
/// <param name="value">value to set</param>
|
|
public void SetFieldOrProperty(string name, BindingFlags bindingFlags, object value)
|
|
{
|
|
this.InvokeHelper(name, BindingFlags.SetField | BindingFlags.SetProperty | bindingFlags, new object[] { value }, CultureInfo.InvariantCulture);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the property
|
|
/// </summary>
|
|
/// <param name="name">Name of the property</param>
|
|
/// <param name="args">Arguments to pass to the member to invoke.</param>
|
|
/// <returns>The property.</returns>
|
|
public object GetProperty(string name, params object[] args)
|
|
{
|
|
return this.GetProperty(name, null, args);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the property
|
|
/// </summary>
|
|
/// <param name="name">Name of the property</param>
|
|
/// <param name="parameterTypes">An array of <see cref="T:System.Type"/> objects representing the number, order, and type of the parameters for the indexed property.</param>
|
|
/// <param name="args">Arguments to pass to the member to invoke.</param>
|
|
/// <returns>The property.</returns>
|
|
public object GetProperty(string name, Type[] parameterTypes, object[] args)
|
|
{
|
|
return this.GetProperty(name, BindToEveryThing, parameterTypes, args);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Set the property
|
|
/// </summary>
|
|
/// <param name="name">Name of the property</param>
|
|
/// <param name="value">value to set</param>
|
|
/// <param name="args">Arguments to pass to the member to invoke.</param>
|
|
public void SetProperty(string name, object value, params object[] args)
|
|
{
|
|
this.SetProperty(name, null, value, args);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Set the property
|
|
/// </summary>
|
|
/// <param name="name">Name of the property</param>
|
|
/// <param name="parameterTypes">An array of <see cref="T:System.Type"/> objects representing the number, order, and type of the parameters for the indexed property.</param>
|
|
/// <param name="value">value to set</param>
|
|
/// <param name="args">Arguments to pass to the member to invoke.</param>
|
|
public void SetProperty(string name, Type[] parameterTypes, object value, object[] args)
|
|
{
|
|
this.SetProperty(name, BindToEveryThing, value, parameterTypes, args);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the property
|
|
/// </summary>
|
|
/// <param name="name">Name of the property</param>
|
|
/// <param name="bindingFlags">A bitmask comprised of one or more <see cref="T:System.Reflection.BindingFlags"/> that specify how the search is conducted.</param>
|
|
/// <param name="args">Arguments to pass to the member to invoke.</param>
|
|
/// <returns>The property.</returns>
|
|
public object GetProperty(string name, BindingFlags bindingFlags, params object[] args)
|
|
{
|
|
return this.GetProperty(name, bindingFlags, null, args);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the property
|
|
/// </summary>
|
|
/// <param name="name">Name of the property</param>
|
|
/// <param name="bindingFlags">A bitmask comprised of one or more <see cref="T:System.Reflection.BindingFlags"/> that specify how the search is conducted.</param>
|
|
/// <param name="parameterTypes">An array of <see cref="T:System.Type"/> objects representing the number, order, and type of the parameters for the indexed property.</param>
|
|
/// <param name="args">Arguments to pass to the member to invoke.</param>
|
|
/// <returns>The property.</returns>
|
|
public object GetProperty(string name, BindingFlags bindingFlags, Type[] parameterTypes, object[] args)
|
|
{
|
|
if (parameterTypes != null)
|
|
{
|
|
PropertyInfo pi = this.originalType.GetProperty(name, bindingFlags, null, null, parameterTypes, null);
|
|
if (pi == null)
|
|
{
|
|
throw new ArgumentException(
|
|
string.Format(CultureInfo.CurrentCulture, "The member specified ({0}) could not be found. You might need to regenerate your private accessor, or the member may be private and defined on a base class. If the latter is true, you need to pass the type that defines the member into PrivateObject's constructor.", name));
|
|
}
|
|
|
|
return pi.GetValue(this.target, args);
|
|
}
|
|
else
|
|
{
|
|
return this.InvokeHelper(name, bindingFlags | BindingFlags.GetProperty, args, null);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Sets the property
|
|
/// </summary>
|
|
/// <param name="name">Name of the property</param>
|
|
/// <param name="bindingFlags">A bitmask comprised of one or more <see cref="T:System.Reflection.BindingFlags"/> that specify how the search is conducted.</param>
|
|
/// <param name="value">value to set</param>
|
|
/// <param name="args">Arguments to pass to the member to invoke.</param>
|
|
public void SetProperty(string name, BindingFlags bindingFlags, object value, params object[] args)
|
|
{
|
|
this.SetProperty(name, bindingFlags, value, null, args);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Sets the property
|
|
/// </summary>
|
|
/// <param name="name">Name of the property</param>
|
|
/// <param name="bindingFlags">A bitmask comprised of one or more <see cref="T:System.Reflection.BindingFlags"/> that specify how the search is conducted.</param>
|
|
/// <param name="value">value to set</param>
|
|
/// <param name="parameterTypes">An array of <see cref="T:System.Type"/> objects representing the number, order, and type of the parameters for the indexed property.</param>
|
|
/// <param name="args">Arguments to pass to the member to invoke.</param>
|
|
public void SetProperty(string name, BindingFlags bindingFlags, object value, Type[] parameterTypes, object[] args)
|
|
{
|
|
if (parameterTypes != null)
|
|
{
|
|
PropertyInfo pi = this.originalType.GetProperty(name, bindingFlags, null, null, parameterTypes, null);
|
|
if (pi == null)
|
|
{
|
|
throw new ArgumentException(
|
|
string.Format(CultureInfo.CurrentCulture, "The member specified ({0}) could not be found. You might need to regenerate your private accessor, or the member may be private and defined on a base class. If the latter is true, you need to pass the type that defines the member into PrivateObject's constructor.", 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);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Validate access string
|
|
/// </summary>
|
|
/// <param name="access"> access string</param>
|
|
private static void ValidateAccessString(string access)
|
|
{
|
|
if (access.Length == 0)
|
|
{
|
|
throw new ArgumentException("Access string has invalid syntax.");
|
|
}
|
|
|
|
string[] arr = access.Split('.');
|
|
foreach (string str in arr)
|
|
{
|
|
if ((str.Length == 0) || (str.IndexOfAny(new char[] { ' ', '\t', '\n' }) != -1))
|
|
{
|
|
throw new ArgumentException("Access string has invalid syntax.");
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Invokes the memeber
|
|
/// </summary>
|
|
/// <param name="name">Name of the member</param>
|
|
/// <param name="bindingFlags">Additional attributes</param>
|
|
/// <param name="args">Arguments for the invocation</param>
|
|
/// <param name="culture">Culture</param>
|
|
/// <returns>Result of the invocation</returns>
|
|
private object InvokeHelper(string name, BindingFlags bindingFlags, object[] args, CultureInfo culture)
|
|
{
|
|
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)
|
|
{
|
|
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<string, LinkedList<MethodInfo>>();
|
|
|
|
MethodInfo[] members = t.GetMethods(BindToEveryThing);
|
|
LinkedList<MethodInfo> 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<MethodInfo>();
|
|
this.GenericMethodCache.Add(member.Name, listByName);
|
|
}
|
|
|
|
Debug.Assert(listByName != null, "list should not be null.");
|
|
listByName.AddLast(member);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Extracts the most appropriate generic method signature from the current private type.
|
|
/// </summary>
|
|
/// <param name="methodName">The name of the method in which to search the signature cache.</param>
|
|
/// <param name="parameterTypes">An array of types corresponding to the types of the parameters in which to search.</param>
|
|
/// <param name="typeArguments">An array of types corresponding to the types of the generic arguments.</param>
|
|
/// <param name="bindingFlags"><see cref="BindingFlags"/> to further filter the method signatures.</param>
|
|
/// <param name="modifiers">Modifiers for parameters.</param>
|
|
/// <returns>A methodinfo instance.</returns>
|
|
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<MethodInfo> 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<MethodInfo> methodCandidates = new LinkedList<MethodInfo>();
|
|
LinkedList<MethodInfo> 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;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// This class represents a private class for the Private Accessor functionality.
|
|
/// </summary>
|
|
public class PrivateType
|
|
{
|
|
/// <summary>
|
|
/// Binds to everything
|
|
/// </summary>
|
|
private const BindingFlags BindToEveryThing = BindingFlags.Default
|
|
| BindingFlags.NonPublic | BindingFlags.Instance
|
|
| BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy;
|
|
|
|
/// <summary>
|
|
/// The wrapped type.
|
|
/// </summary>
|
|
private Type type;
|
|
|
|
/// <summary>
|
|
/// Initializes a new instance of the <see cref="PrivateType"/> class that contains the private type.
|
|
/// </summary>
|
|
/// <param name="assemblyName">Assembly name</param>
|
|
/// <param name="typeName">fully qualified name of the </param>
|
|
public PrivateType(string assemblyName, string typeName)
|
|
{
|
|
Assembly asm = Assembly.Load(assemblyName);
|
|
|
|
this.type = asm.GetType(typeName, true);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Initializes a new instance of the <see cref="PrivateType"/> class that contains
|
|
/// the private type from the type object
|
|
/// </summary>
|
|
/// <param name="type">The wrapped Type to create.</param>
|
|
public PrivateType(Type type)
|
|
{
|
|
if (type == null)
|
|
{
|
|
throw new ArgumentNullException("type");
|
|
}
|
|
|
|
this.type = type;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the referenced type
|
|
/// </summary>
|
|
public Type ReferencedType => this.type;
|
|
|
|
/// <summary>
|
|
/// Invokes static member
|
|
/// </summary>
|
|
/// <param name="name">Name of the member to InvokeHelper</param>
|
|
/// <param name="args">Arguements to the invoction</param>
|
|
/// <returns>Result of invocation</returns>
|
|
public object InvokeStatic(string name, params object[] args)
|
|
{
|
|
return this.InvokeStatic(name, null, args, CultureInfo.InvariantCulture);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Invokes static member
|
|
/// </summary>
|
|
/// <param name="name">Name of the member to InvokeHelper</param>
|
|
/// <param name="parameterTypes">An array of <see cref="T:System.Type"/> objects representing the number, order, and type of the parameters for the method to invoke</param>
|
|
/// <param name="args">Arguements to the invoction</param>
|
|
/// <returns>Result of invocation</returns>
|
|
public object InvokeStatic(string name, Type[] parameterTypes, object[] args)
|
|
{
|
|
return this.InvokeStatic(name, parameterTypes, args, CultureInfo.InvariantCulture);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Invokes static member
|
|
/// </summary>
|
|
/// <param name="name">Name of the member to InvokeHelper</param>
|
|
/// <param name="parameterTypes">An array of <see cref="T:System.Type"/> objects representing the number, order, and type of the parameters for the method to invoke</param>
|
|
/// <param name="args">Arguements to the invoction</param>
|
|
/// <param name="typeArguments">An array of types corresponding to the types of the generic arguments.</param>
|
|
/// <returns>Result of invocation</returns>
|
|
public object InvokeStatic(string name, Type[] parameterTypes, object[] args, Type[] typeArguments)
|
|
{
|
|
return this.InvokeStatic(name, BindToEveryThing, parameterTypes, args, CultureInfo.InvariantCulture, typeArguments);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Invokes the static method
|
|
/// </summary>
|
|
/// <param name="name">Name of the member</param>
|
|
/// <param name="args">Arguements to the invocation</param>
|
|
/// <param name="culture">Culture</param>
|
|
/// <returns>Result of invocation</returns>
|
|
public object InvokeStatic(string name, object[] args, CultureInfo culture)
|
|
{
|
|
return this.InvokeStatic(name, null, args, culture);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Invokes the static method
|
|
/// </summary>
|
|
/// <param name="name">Name of the member</param>
|
|
/// <param name="parameterTypes">An array of <see cref="T:System.Type"/> objects representing the number, order, and type of the parameters for the method to invoke</param>
|
|
/// <param name="args">Arguements to the invocation</param>
|
|
/// <param name="culture">Culture info</param>
|
|
/// <returns>Result of invocation</returns>
|
|
public object InvokeStatic(string name, Type[] parameterTypes, object[] args, CultureInfo culture)
|
|
{
|
|
return this.InvokeStatic(name, BindingFlags.InvokeMethod, parameterTypes, args, culture);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Invokes the static method
|
|
/// </summary>
|
|
/// <param name="name">Name of the member</param>
|
|
/// <param name="bindingFlags">Additional invocation attributes</param>
|
|
/// <param name="args">Arguements to the invocation</param>
|
|
/// <returns>Result of invocation</returns>
|
|
public object InvokeStatic(string name, BindingFlags bindingFlags, params object[] args)
|
|
{
|
|
return this.InvokeStatic(name, bindingFlags, null, args, CultureInfo.InvariantCulture);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Invokes the static method
|
|
/// </summary>
|
|
/// <param name="name">Name of the member</param>
|
|
/// <param name="bindingFlags">Additional invocation attributes</param>
|
|
/// <param name="parameterTypes">An array of <see cref="T:System.Type"/> objects representing the number, order, and type of the parameters for the method to invoke</param>
|
|
/// <param name="args">Arguements to the invocation</param>
|
|
/// <returns>Result of invocation</returns>
|
|
public object InvokeStatic(string name, BindingFlags bindingFlags, Type[] parameterTypes, object[] args)
|
|
{
|
|
return this.InvokeStatic(name, bindingFlags, parameterTypes, args, CultureInfo.InvariantCulture);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Invokes the static method
|
|
/// </summary>
|
|
/// <param name="name">Name of the member</param>
|
|
/// <param name="bindingFlags">Additional invocation attributes</param>
|
|
/// <param name="args">Arguements to the invocation</param>
|
|
/// <param name="culture">Culture</param>
|
|
/// <returns>Result of invocation</returns>
|
|
public object InvokeStatic(string name, BindingFlags bindingFlags, object[] args, CultureInfo culture)
|
|
{
|
|
return this.InvokeStatic(name, bindingFlags, null, args, culture);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Invokes the static method
|
|
/// </summary>
|
|
/// <param name="name">Name of the member</param>
|
|
/// <param name="bindingFlags">Additional invocation attributes</param>
|
|
/// /// <param name="parameterTypes">An array of <see cref="T:System.Type"/> objects representing the number, order, and type of the parameters for the method to invoke</param>
|
|
/// <param name="args">Arguements to the invocation</param>
|
|
/// <param name="culture">Culture</param>
|
|
/// <returns>Result of invocation</returns>
|
|
public object InvokeStatic(string name, BindingFlags bindingFlags, Type[] parameterTypes, object[] args, CultureInfo culture)
|
|
{
|
|
return this.InvokeStatic(name, bindingFlags, parameterTypes, args, culture, null);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Invokes the static method
|
|
/// </summary>
|
|
/// <param name="name">Name of the member</param>
|
|
/// <param name="bindingFlags">Additional invocation attributes</param>
|
|
/// /// <param name="parameterTypes">An array of <see cref="T:System.Type"/> objects representing the number, order, and type of the parameters for the method to invoke</param>
|
|
/// <param name="args">Arguements to the invocation</param>
|
|
/// <param name="culture">Culture</param>
|
|
/// <param name="typeArguments">An array of types corresponding to the types of the generic arguments.</param>
|
|
/// <returns>Result of invocation</returns>
|
|
public object InvokeStatic(string name, BindingFlags bindingFlags, Type[] parameterTypes, object[] args, CultureInfo culture, Type[] typeArguments)
|
|
{
|
|
if (parameterTypes != null)
|
|
{
|
|
MethodInfo member = this.type.GetMethod(name, bindingFlags | BindToEveryThing | BindingFlags.Static, null, parameterTypes, null);
|
|
if (member == null)
|
|
{
|
|
throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, "The member specified ({0}) could not be found. You might need to regenerate your private accessor, or the member may be private and defined on a base class. If the latter is true, you need to pass the type that defines the member into PrivateObject's constructor.", name));
|
|
}
|
|
|
|
try
|
|
{
|
|
if (member.IsGenericMethodDefinition)
|
|
{
|
|
MethodInfo constructed = member.MakeGenericMethod(typeArguments);
|
|
return constructed.Invoke(null, bindingFlags, null, args, culture);
|
|
}
|
|
else
|
|
{
|
|
return member.Invoke(null, 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.InvokeHelperStatic(name, bindingFlags | BindingFlags.InvokeMethod, args, culture);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the element in static array
|
|
/// </summary>
|
|
/// <param name="name">Name of the array</param>
|
|
/// <param name="indices">
|
|
/// A one-dimensional array of 32-bit integers that represent the indexes specifying
|
|
/// the position of the element to get. For instance, to access a[10][11] the indices would be {10,11}
|
|
/// </param>
|
|
/// <returns>element at the specified location</returns>
|
|
public object GetStaticArrayElement(string name, params int[] indices)
|
|
{
|
|
return this.GetStaticArrayElement(name, BindToEveryThing, indices);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Sets the memeber of the static array
|
|
/// </summary>
|
|
/// <param name="name">Name of the array</param>
|
|
/// <param name="value">value to set</param>
|
|
/// <param name="indices">
|
|
/// A one-dimensional array of 32-bit integers that represent the indexes specifying
|
|
/// the position of the element to set. For instance, to access a[10][11] the array would be {10,11}
|
|
/// </param>
|
|
public void SetStaticArrayElement(string name, object value, params int[] indices)
|
|
{
|
|
this.SetStaticArrayElement(name, BindToEveryThing, value, indices);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the element in satatic array
|
|
/// </summary>
|
|
/// <param name="name">Name of the array</param>
|
|
/// <param name="bindingFlags">Additional InvokeHelper attributes</param>
|
|
/// <param name="indices">
|
|
/// A one-dimensional array of 32-bit integers that represent the indexes specifying
|
|
/// the position of the element to get. For instance, to access a[10][11] the array would be {10,11}
|
|
/// </param>
|
|
/// <returns>element at the spcified location</returns>
|
|
public object GetStaticArrayElement(string name, BindingFlags bindingFlags, params int[] indices)
|
|
{
|
|
Array arr = (Array)this.InvokeHelperStatic(name, BindingFlags.GetField | BindingFlags.GetProperty | bindingFlags, null, CultureInfo.InvariantCulture);
|
|
return arr.GetValue(indices);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Sets the memeber of the static array
|
|
/// </summary>
|
|
/// <param name="name">Name of the array</param>
|
|
/// <param name="bindingFlags">Additional InvokeHelper attributes</param>
|
|
/// <param name="value">value to set</param>
|
|
/// <param name="indices">
|
|
/// A one-dimensional array of 32-bit integers that represent the indexes specifying
|
|
/// the position of the element to set. For instance, to access a[10][11] the array would be {10,11}
|
|
/// </param>
|
|
public void SetStaticArrayElement(string name, BindingFlags bindingFlags, object value, params int[] indices)
|
|
{
|
|
Array arr = (Array)this.InvokeHelperStatic(name, BindingFlags.GetField | BindingFlags.GetProperty | BindingFlags.Static | bindingFlags, null, CultureInfo.InvariantCulture);
|
|
arr.SetValue(value, indices);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the static field
|
|
/// </summary>
|
|
/// <param name="name">Name of the field</param>
|
|
/// <returns>The static field.</returns>
|
|
public object GetStaticField(string name)
|
|
{
|
|
return this.GetStaticField(name, BindToEveryThing);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Sets the static field
|
|
/// </summary>
|
|
/// <param name="name">Name of the field</param>
|
|
/// <param name="value">Arguement to the invocation</param>
|
|
public void SetStaticField(string name, object value)
|
|
{
|
|
this.SetStaticField(name, BindToEveryThing, value);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the static field using specified InvokeHelper attributes
|
|
/// </summary>
|
|
/// <param name="name">Name of the field</param>
|
|
/// <param name="bindingFlags">Additional invocation attributes</param>
|
|
/// <returns>The static field.</returns>
|
|
public object GetStaticField(string name, BindingFlags bindingFlags)
|
|
{
|
|
return this.InvokeHelperStatic(name, BindingFlags.GetField | BindingFlags.Static | bindingFlags, null, CultureInfo.InvariantCulture);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Sets the static field using binding attributes
|
|
/// </summary>
|
|
/// <param name="name">Name of the field</param>
|
|
/// <param name="bindingFlags">Additional InvokeHelper attributes</param>
|
|
/// <param name="value">Arguement to the invocation</param>
|
|
public void SetStaticField(string name, BindingFlags bindingFlags, object value)
|
|
{
|
|
this.InvokeHelperStatic(name, BindingFlags.SetField | bindingFlags | BindingFlags.Static, new[] { value }, CultureInfo.InvariantCulture);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the static field or property
|
|
/// </summary>
|
|
/// <param name="name">Name of the field or property</param>
|
|
/// <returns>The static field or property.</returns>
|
|
public object GetStaticFieldOrProperty(string name)
|
|
{
|
|
return this.GetStaticFieldOrProperty(name, BindToEveryThing);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Sets the static field or property
|
|
/// </summary>
|
|
/// <param name="name">Name of the field or property</param>
|
|
/// <param name="value">Value to be set to field or property</param>
|
|
public void SetStaticFieldOrProperty(string name, object value)
|
|
{
|
|
this.SetStaticFieldOrProperty(name, BindToEveryThing, value);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the static field or property using specified InvokeHelper attributes
|
|
/// </summary>
|
|
/// <param name="name">Name of the field or property</param>
|
|
/// <param name="bindingFlags">Additional invocation attributes</param>
|
|
/// <returns>The static field or property.</returns>
|
|
public object GetStaticFieldOrProperty(string name, BindingFlags bindingFlags)
|
|
{
|
|
return this.InvokeHelperStatic(name, BindingFlags.GetField | BindingFlags.GetProperty | BindingFlags.Static | bindingFlags, null, CultureInfo.InvariantCulture);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Sets the static field or property using binding attributes
|
|
/// </summary>
|
|
/// <param name="name">Name of the field or property</param>
|
|
/// <param name="bindingFlags">Additional invocation attributes</param>
|
|
/// <param name="value">Value to be set to field or property</param>
|
|
public void SetStaticFieldOrProperty(string name, BindingFlags bindingFlags, object value)
|
|
{
|
|
this.InvokeHelperStatic(name, BindingFlags.SetField | BindingFlags.SetProperty | bindingFlags | BindingFlags.Static, new[] { value }, CultureInfo.InvariantCulture);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the static property
|
|
/// </summary>
|
|
/// <param name="name">Name of the field or property</param>
|
|
/// <param name="args">Arguements to the invocation</param>
|
|
/// <returns>The static property.</returns>
|
|
public object GetStaticProperty(string name, params object[] args)
|
|
{
|
|
return this.GetStaticProperty(name, BindToEveryThing, args);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Sets the static property
|
|
/// </summary>
|
|
/// <param name="name">Name of the property</param>
|
|
/// <param name="value">Value to be set to field or property</param>
|
|
/// <param name="args">Arguments to pass to the member to invoke.</param>
|
|
public void SetStaticProperty(string name, object value, params object[] args)
|
|
{
|
|
this.SetStaticProperty(name, BindToEveryThing, value, null, args);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Sets the static property
|
|
/// </summary>
|
|
/// <param name="name">Name of the property</param>
|
|
/// <param name="value">Value to be set to field or property</param>
|
|
/// <param name="parameterTypes">An array of <see cref="T:System.Type"/> objects representing the number, order, and type of the parameters for the indexed property.</param>
|
|
/// <param name="args">Arguments to pass to the member to invoke.</param>
|
|
public void SetStaticProperty(string name, object value, Type[] parameterTypes, object[] args)
|
|
{
|
|
this.SetStaticProperty(name, BindingFlags.SetProperty, value, parameterTypes, args);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the static property
|
|
/// </summary>
|
|
/// <param name="name">Name of the property</param>
|
|
/// <param name="bindingFlags">Additional invocation attributes.</param>
|
|
/// <param name="args">Arguments to pass to the member to invoke.</param>
|
|
/// <returns>The static property.</returns>
|
|
public object GetStaticProperty(string name, BindingFlags bindingFlags, params object[] args)
|
|
{
|
|
return this.GetStaticProperty(name, BindingFlags.GetProperty | BindingFlags.Static | bindingFlags, null, args);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the static property
|
|
/// </summary>
|
|
/// <param name="name">Name of the property</param>
|
|
/// <param name="bindingFlags">Additional invocation attributes.</param>
|
|
/// <param name="parameterTypes">An array of <see cref="T:System.Type"/> objects representing the number, order, and type of the parameters for the indexed property.</param>
|
|
/// <param name="args">Arguments to pass to the member to invoke.</param>
|
|
/// <returns>The static property.</returns>
|
|
public object GetStaticProperty(string name, BindingFlags bindingFlags, Type[] parameterTypes, object[] args)
|
|
{
|
|
if (parameterTypes != null)
|
|
{
|
|
PropertyInfo pi = this.type.GetProperty(name, bindingFlags | BindingFlags.Static, null, null, parameterTypes, null);
|
|
if (pi == null)
|
|
{
|
|
throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, "The member specified ({0}) could not be found. You might need to regenerate your private accessor, or the member may be private and defined on a base class. If the latter is true, you need to pass the type that defines the member into PrivateObject's constructor.", name));
|
|
}
|
|
|
|
return pi.GetValue(null, args);
|
|
}
|
|
else
|
|
{
|
|
return this.InvokeHelperStatic(name, bindingFlags | BindingFlags.GetProperty, args, null);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Sets the static property
|
|
/// </summary>
|
|
/// <param name="name">Name of the property</param>
|
|
/// <param name="bindingFlags">Additional invocation attributes.</param>
|
|
/// <param name="value">Value to be set to field or property</param>
|
|
/// <param name="args">Optional index values for indexed properties. The indexes of indexed properties are zero-based. This value should be null for non-indexed properties. </param>
|
|
public void SetStaticProperty(string name, BindingFlags bindingFlags, object value, params object[] args)
|
|
{
|
|
this.SetStaticProperty(name, bindingFlags, value, null, args);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Sets the static property
|
|
/// </summary>
|
|
/// <param name="name">Name of the property</param>
|
|
/// <param name="bindingFlags">Additional invocation attributes.</param>
|
|
/// <param name="value">Value to be set to field or property</param>
|
|
/// <param name="parameterTypes">An array of <see cref="T:System.Type"/> objects representing the number, order, and type of the parameters for the indexed property.</param>
|
|
/// <param name="args">Arguments to pass to the member to invoke.</param>
|
|
public void SetStaticProperty(string name, BindingFlags bindingFlags, object value, Type[] parameterTypes, object[] args)
|
|
{
|
|
if (parameterTypes != null)
|
|
{
|
|
PropertyInfo pi = this.type.GetProperty(name, bindingFlags | BindingFlags.Static, null, null, parameterTypes, null);
|
|
if (pi == null)
|
|
{
|
|
throw new ArgumentException(
|
|
string.Format(CultureInfo.CurrentCulture, "The member specified ({0}) could not be found. You might need to regenerate your private accessor, or the member may be private and defined on a base class. If the latter is true, you need to pass the type that defines the member into PrivateObject's constructor.", name));
|
|
}
|
|
|
|
pi.SetValue(null, value, args);
|
|
}
|
|
else
|
|
{
|
|
object[] pass = new object[(args?.Length ?? 0) + 1];
|
|
pass[0] = value;
|
|
args?.CopyTo(pass, 1);
|
|
this.InvokeHelperStatic(name, bindingFlags | BindingFlags.SetProperty, pass, null);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Invokes the static method
|
|
/// </summary>
|
|
/// <param name="name">Name of the member</param>
|
|
/// <param name="bindingFlags">Additional invocation attributes</param>
|
|
/// <param name="args">Arguements to the invocation</param>
|
|
/// <param name="culture">Culture</param>
|
|
/// <returns>Result of invocation</returns>
|
|
private object InvokeHelperStatic(string name, BindingFlags bindingFlags, object[] args, CultureInfo culture)
|
|
{
|
|
try
|
|
{
|
|
return this.type.InvokeMember(name, bindingFlags | BindToEveryThing | BindingFlags.Static, null, 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;
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Provides method signature discovery for generic methods.
|
|
/// </summary>
|
|
internal class RuntimeTypeHelper
|
|
{
|
|
/// <summary>
|
|
/// Compares the method signatures of these two methods.
|
|
/// </summary>
|
|
/// <param name="m1">Method1</param>
|
|
/// <param name="m2">Method2</param>
|
|
/// <returns>True if they are similiar.</returns>
|
|
internal static bool CompareMethodSigAndName(MethodBase m1, MethodBase m2)
|
|
{
|
|
ParameterInfo[] params1 = m1.GetParameters();
|
|
ParameterInfo[] params2 = m2.GetParameters();
|
|
|
|
if (params1.Length != params2.Length)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
int numParams = params1.Length;
|
|
for (int i = 0; i < numParams; i++)
|
|
{
|
|
if (params1[i].ParameterType != params2[i].ParameterType)
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the hierarchy depth from the base type of the provided type.
|
|
/// </summary>
|
|
/// <param name="t">The type.</param>
|
|
/// <returns>The depth.</returns>
|
|
internal static int GetHierarchyDepth(Type t)
|
|
{
|
|
int depth = 0;
|
|
|
|
Type currentType = t;
|
|
do
|
|
{
|
|
depth++;
|
|
currentType = currentType.BaseType;
|
|
}
|
|
while (currentType != null);
|
|
|
|
return depth;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Finds most dervied type with the provided information.
|
|
/// </summary>
|
|
/// <param name="match">Candidate matches.</param>
|
|
/// <param name="cMatches">Number of matches.</param>
|
|
/// <returns>The most derived method.</returns>
|
|
internal static MethodBase FindMostDerivedNewSlotMeth(MethodBase[] match, int cMatches)
|
|
{
|
|
int deepestHierarchy = 0;
|
|
MethodBase methWithDeepestHierarchy = null;
|
|
|
|
for (int i = 0; i < cMatches; i++)
|
|
{
|
|
// Calculate the depth of the hierarchy of the declaring type of the
|
|
// current method.
|
|
int currentHierarchyDepth = GetHierarchyDepth(match[i].DeclaringType);
|
|
|
|
// Two methods with the same hierarchy depth are not allowed. This would
|
|
// mean that there are 2 methods with the same name and sig on a given type
|
|
// which is not allowed, unless one of them is vararg...
|
|
if (currentHierarchyDepth == deepestHierarchy)
|
|
{
|
|
if (methWithDeepestHierarchy != null)
|
|
{
|
|
Debug.Assert(
|
|
methWithDeepestHierarchy != null && ((match[i].CallingConvention & CallingConventions.VarArgs)
|
|
| (methWithDeepestHierarchy.CallingConvention & CallingConventions.VarArgs)) != 0,
|
|
"Calling conventions: " + match[i].CallingConvention + " - " + methWithDeepestHierarchy.CallingConvention);
|
|
}
|
|
|
|
throw new AmbiguousMatchException();
|
|
}
|
|
|
|
// Check to see if this method is on the most derived class.
|
|
if (currentHierarchyDepth > deepestHierarchy)
|
|
{
|
|
deepestHierarchy = currentHierarchyDepth;
|
|
methWithDeepestHierarchy = match[i];
|
|
}
|
|
}
|
|
|
|
return methWithDeepestHierarchy;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Given a set of methods that match the base criteria, select a method based
|
|
/// upon an array of types. This method should return null if no method matches
|
|
/// the criteria.
|
|
/// </summary>
|
|
/// <param name="bindingAttr">Binding specification.</param>
|
|
/// <param name="match">Candidate matches</param>
|
|
/// <param name="types">Types</param>
|
|
/// <param name="modifiers">Parameter modifiers.</param>
|
|
/// <returns>Matching method. Null if none matches.</returns>
|
|
internal static MethodBase SelectMethod(BindingFlags bindingAttr, MethodBase[] match, Type[] types, ParameterModifier[] modifiers)
|
|
{
|
|
if (match == null)
|
|
{
|
|
throw new ArgumentNullException("match");
|
|
}
|
|
|
|
int i;
|
|
int j;
|
|
|
|
Type[] realTypes = new Type[types.Length];
|
|
for (i = 0; i < types.Length; i++)
|
|
{
|
|
realTypes[i] = types[i].UnderlyingSystemType;
|
|
}
|
|
|
|
types = realTypes;
|
|
|
|
// If there are no methods to match to, then return null, indicating that no method
|
|
// matches the criteria
|
|
if (match.Length == 0)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
// Find all the methods that can be described by the types parameter.
|
|
// Remove all of them that cannot.
|
|
int curIdx = 0;
|
|
for (i = 0; i < match.Length; i++)
|
|
{
|
|
ParameterInfo[] par = match[i].GetParameters();
|
|
if (par.Length != types.Length)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
for (j = 0; j < types.Length; j++)
|
|
{
|
|
Type pCls = par[j].ParameterType;
|
|
|
|
if (pCls.ContainsGenericParameters)
|
|
{
|
|
if (pCls.IsArray != types[j].IsArray)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (pCls == types[j])
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (pCls == typeof(object))
|
|
{
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
if (!pCls.IsAssignableFrom(types[j]))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (j == types.Length)
|
|
{
|
|
match[curIdx++] = match[i];
|
|
}
|
|
}
|
|
|
|
if (curIdx == 0)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
if (curIdx == 1)
|
|
{
|
|
return match[0];
|
|
}
|
|
|
|
// Walk all of the methods looking the most specific method to invoke
|
|
int currentMin = 0;
|
|
bool ambig = false;
|
|
int[] paramOrder = new int[types.Length];
|
|
for (i = 0; i < types.Length; i++)
|
|
{
|
|
paramOrder[i] = i;
|
|
}
|
|
|
|
for (i = 1; i < curIdx; i++)
|
|
{
|
|
int newMin = FindMostSpecificMethod(match[currentMin], paramOrder, null, match[i], paramOrder, null, types, null);
|
|
if (newMin == 0)
|
|
{
|
|
ambig = true;
|
|
}
|
|
else
|
|
{
|
|
if (newMin == 2)
|
|
{
|
|
currentMin = i;
|
|
ambig = false;
|
|
currentMin = i;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (ambig)
|
|
{
|
|
throw new AmbiguousMatchException();
|
|
}
|
|
|
|
return match[currentMin];
|
|
}
|
|
|
|
/// <summary>
|
|
/// Finds the most specific method in the two methods provided.
|
|
/// </summary>
|
|
/// <param name="m1">Method 1</param>
|
|
/// <param name="paramOrder1">Parameter order for Method 1</param>
|
|
/// <param name="paramArrayType1">Paramter array type.</param>
|
|
/// <param name="m2">Method 2</param>
|
|
/// <param name="paramOrder2">Parameter order for Method 2</param>
|
|
/// <param name="paramArrayType2">>Paramter array type.</param>
|
|
/// <param name="types">Types to search in.</param>
|
|
/// <param name="args">Args.</param>
|
|
/// <returns>An int representing the match.</returns>
|
|
internal static int FindMostSpecificMethod(
|
|
MethodBase m1,
|
|
int[] paramOrder1,
|
|
Type paramArrayType1,
|
|
MethodBase m2,
|
|
int[] paramOrder2,
|
|
Type paramArrayType2,
|
|
Type[] types,
|
|
object[] args)
|
|
{
|
|
// Find the most specific method based on the parameters.
|
|
int res = FindMostSpecific(
|
|
m1.GetParameters(),
|
|
paramOrder1,
|
|
paramArrayType1,
|
|
m2.GetParameters(),
|
|
paramOrder2,
|
|
paramArrayType2,
|
|
types,
|
|
args);
|
|
|
|
// If the match was not ambiguous then return the result.
|
|
if (res != 0)
|
|
{
|
|
return res;
|
|
}
|
|
|
|
// Check to see if the methods have the exact same name and signature.
|
|
if (CompareMethodSigAndName(m1, m2))
|
|
{
|
|
// Determine the depth of the declaring types for both methods.
|
|
int hierarchyDepth1 = GetHierarchyDepth(m1.DeclaringType);
|
|
int hierarchyDepth2 = GetHierarchyDepth(m2.DeclaringType);
|
|
|
|
// The most derived method is the most specific one.
|
|
if (hierarchyDepth1 == hierarchyDepth2)
|
|
{
|
|
return 0;
|
|
}
|
|
else if (hierarchyDepth1 < hierarchyDepth2)
|
|
{
|
|
return 2;
|
|
}
|
|
else
|
|
{
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
// The match is ambiguous.
|
|
return 0;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Finds the most specific method in the two methods provided.
|
|
/// </summary>
|
|
/// <param name="p1">Method 1</param>
|
|
/// <param name="paramOrder1">Parameter order for Method 1</param>
|
|
/// <param name="paramArrayType1">Paramter array type.</param>
|
|
/// <param name="p2">Method 2</param>
|
|
/// <param name="paramOrder2">Parameter order for Method 2</param>
|
|
/// <param name="paramArrayType2">>Paramter array type.</param>
|
|
/// <param name="types">Types to search in.</param>
|
|
/// <param name="args">Args.</param>
|
|
/// <returns>An int representing the match.</returns>
|
|
internal static int FindMostSpecific(
|
|
ParameterInfo[] p1,
|
|
int[] paramOrder1,
|
|
Type paramArrayType1,
|
|
ParameterInfo[] p2,
|
|
int[] paramOrder2,
|
|
Type paramArrayType2,
|
|
Type[] types,
|
|
object[] args)
|
|
{
|
|
// A method using params is always less specific than one not using params
|
|
if (paramArrayType1 != null && paramArrayType2 == null)
|
|
{
|
|
return 2;
|
|
}
|
|
|
|
if (paramArrayType2 != null && paramArrayType1 == null)
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
bool p1Less = false;
|
|
bool p2Less = false;
|
|
|
|
for (int i = 0; i < types.Length; i++)
|
|
{
|
|
if (args != null && args[i] == Type.Missing)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
Type c1, c2;
|
|
|
|
// If a param array is present, then either
|
|
// the user re-ordered the parameters in which case
|
|
// the argument to the param array is either an array
|
|
// in which case the params is conceptually ignored and so paramArrayType1 == null
|
|
// or the argument to the param array is a single element
|
|
// in which case paramOrder[i] == p1.Length - 1 for that element
|
|
// or the user did not re-order the parameters in which case
|
|
// the paramOrder array could contain indexes larger than p.Length - 1
|
|
//// so any index >= p.Length - 1 is being put in the param array
|
|
|
|
if (paramArrayType1 != null && paramOrder1[i] >= p1.Length - 1)
|
|
{
|
|
c1 = paramArrayType1;
|
|
}
|
|
else
|
|
{
|
|
c1 = p1[paramOrder1[i]].ParameterType;
|
|
}
|
|
|
|
if (paramArrayType2 != null && paramOrder2[i] >= p2.Length - 1)
|
|
{
|
|
c2 = paramArrayType2;
|
|
}
|
|
else
|
|
{
|
|
c2 = p2[paramOrder2[i]].ParameterType;
|
|
}
|
|
|
|
if (c1 == c2)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (c1.ContainsGenericParameters || c2.ContainsGenericParameters)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
switch (FindMostSpecificType(c1, c2, types[i]))
|
|
{
|
|
case 0:
|
|
return 0;
|
|
case 1:
|
|
p1Less = true;
|
|
break;
|
|
case 2:
|
|
p2Less = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Two way p1Less and p2Less can be equal. All the arguments are the
|
|
// same they both equal false, otherwise there were things that both
|
|
// were the most specific type on....
|
|
if (p1Less == p2Less)
|
|
{
|
|
// it's possible that the 2 methods have same sig and default param in which case we match the one
|
|
// with the same number of args but only if they were exactly the same (that is p1Less and p2Lees are both false)
|
|
if (!p1Less && p1.Length != p2.Length && args != null)
|
|
{
|
|
if (p1.Length == args.Length)
|
|
{
|
|
return 1;
|
|
}
|
|
else if (p2.Length == args.Length)
|
|
{
|
|
return 2;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
else
|
|
{
|
|
return (p1Less == true) ? 1 : 2;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Finds the most specific type in the two provided.
|
|
/// </summary>
|
|
/// <param name="c1">Type 1</param>
|
|
/// <param name="c2">Type 2</param>
|
|
/// <param name="t">The defining type</param>
|
|
/// <returns>An int representing the match.</returns>
|
|
internal static int FindMostSpecificType(Type c1, Type c2, Type t)
|
|
{
|
|
// If the two types are exact move on...
|
|
if (c1 == c2)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
if (c1 == t)
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
if (c2 == t)
|
|
{
|
|
return 2;
|
|
}
|
|
|
|
bool c1FromC2;
|
|
bool c2FromC1;
|
|
|
|
if (c1.IsByRef || c2.IsByRef)
|
|
{
|
|
if (c1.IsByRef && c2.IsByRef)
|
|
{
|
|
c1 = c1.GetElementType();
|
|
c2 = c2.GetElementType();
|
|
}
|
|
else if (c1.IsByRef)
|
|
{
|
|
if (c1.GetElementType() == c2)
|
|
{
|
|
return 2;
|
|
}
|
|
|
|
c1 = c1.GetElementType();
|
|
}
|
|
else
|
|
{
|
|
if (c2.GetElementType() == c1)
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
c2 = c2.GetElementType();
|
|
}
|
|
}
|
|
|
|
if (c1.IsPrimitive && c2.IsPrimitive)
|
|
{
|
|
c1FromC2 = true;
|
|
c2FromC1 = true;
|
|
}
|
|
else
|
|
{
|
|
c1FromC2 = c1.IsAssignableFrom(c2);
|
|
c2FromC1 = c2.IsAssignableFrom(c1);
|
|
}
|
|
|
|
if (c1FromC2 == c2FromC1)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
if (c1FromC2)
|
|
{
|
|
return 2;
|
|
}
|
|
else
|
|
{
|
|
return 1;
|
|
}
|
|
}
|
|
}
|
|
} |