using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Reflection;
using Chernobyl.Collections.Generic.Event;
using Chernobyl.Event;
using Chernobyl.Utility;
using Chernobyl.Values;
namespace Chernobyl.Reflection
{
///
/// Represents the value of a return parameter on a method or constructor.
///
/// The return type of the method to be called.
public class ReturnValue : HeldValue
{
///
/// Initializes a new instance of the class
/// whose is static and takes no parameters.
///
/// The method or constructor to invoke to
/// retrieve the return value.
public ReturnValue(MethodBase method)
: this(method, DecoratingEventEnumerable>.Empty)
{ }
///
/// Initializes a new instance of the class
/// whose is static.
///
/// The method or constructor to invoke to
/// retrieve the return value.
/// An argument list for the invoked method or
/// constructor. This is an sequence of objects with the same number,
/// order, and type as the parameters of the method or constructor to be
/// invoked. If there are no parameters, this should be null. If the
/// method or constructor represented by this instance takes a ByRef
/// parameter, there is no special attribute required for that parameter
/// in order to invoke the method or constructor using this function.
/// Any object in this array that is not explicitly initialized with a
/// value will contain the default value for that object type. For
/// reference-type elements, this value is null. For value-type elements,
/// this value is 0, 0.0, or false, depending on the specific element type.
public ReturnValue(MethodBase method,
IEventEnumerable> parameters)
: this(Values.Value.Null(), method, parameters)
{ }
///
/// Initializes a new instance of the class.
///
/// The containing the
/// object on which to invoke the method or constructor. If a method is
/// static, this argument is ignored. If a constructor is static, the
/// instance contained within the must be null
/// or an instance of the class that defines the constructor.
/// The method or constructor to invoke to
/// retrieve the return value.
/// An argument list for the invoked method or
/// constructor. This is an sequence of objects with the same number,
/// order, and type as the parameters of the method or constructor to be
/// invoked. If there are no parameters, this should be null. If the
/// method or constructor represented by this instance takes a ByRef
/// parameter, there is no special attribute required for that parameter
/// in order to invoke the method or constructor using this function.
/// Any object in this array that is not explicitly initialized with a
/// value will contain the default value for that object type. For
/// reference-type elements, this value is null. For value-type elements,
/// this value is 0, 0.0, or false, depending on the specific element type.
public ReturnValue(IValue instance,
MethodBase method,
IEventEnumerable> parameters)
: this(instance, method, BindingFlags.Default, null,
parameters, null)
{}
///
/// Initializes a new instance of the class.
///
/// The containing the
/// object on which to invoke the method or constructor. If a method is
/// static, this argument is ignored. If a constructor is static, the
/// instance contained within the must be null
/// or an instance of the class that defines the constructor.
/// The method or constructor to invoke to retrieve
/// the return value.
/// A bitmask that is a combination of 0
/// or more bit flags from . If binder is
/// null, this parameter is assigned the value
/// ; thus, whatever you pass in is
/// ignored.
/// An object that enables the binding, coercion of
/// argument types, invocation of members, and retrieval of
/// objects via reflection. If binder is null,
/// the default binder is used.
/// An argument list for the invoked method or
/// constructor. This is an sequence of objects with the same number,
/// order, and type as the parameters of the method or constructor to be
/// invoked. If there are no parameters, this should be null. If the
/// method or constructor represented by this instance takes a ByRef
/// parameter, there is no special attribute required for that parameter
/// in order to invoke the method or constructor using this function.
/// Any object in this array that is not explicitly initialized with a
/// value will contain the default value for that object type. For
/// reference-type elements, this value is null. For value-type elements,
/// this value is 0, 0.0, or false, depending on the specific element type.
/// An instance of used
/// to govern the coercion of types. If this is null, the CultureInfo
/// for the current thread is used. (This is necessary to convert a
/// that represents 1000 to a Double value, for
/// example, since 1000 is represented differently by different cultures.)
public ReturnValue(IValue instance,
MethodBase method,
BindingFlags invokeAttributes,
Binder binder,
IEventEnumerable> parameters,
CultureInfo culture)
{
instance.ThrowIfNull("instance");
method.ThrowIfNull("method");
parameters.ThrowIfNull("parameters");
_instance = instance;
_method = method;
_invokeAttributes = invokeAttributes;
_binder = binder;
_parameters = parameters;
_culture = culture;
// Create a Composite which consists of the instance to invoke
// the method on as the first value and the parameters making up the
// rest of the collection. This Composite will make accessing the
// values easier.
var instanceList = new DecoratingEventList>(new[] {_instance});
_instanceAndParameters = instanceList.Concat(_parameters).AsValues();
}
///
/// Updates the value contained within this .
/// Invokes the method whose return value this instance represents and
/// stores that return value, invoking
/// when the value has been set.
///
public void Update()
{
// Make sure we have the instance to invoke on and the parameters.
if (_instanceAndParameters.Count() == (_parameters.Count() + 1))
{
// Grab the instance to invoke the method on and the parameters. The
// instance will be the first parameter in _instanceAndParametersValues.
Object instance = _instanceAndParameters.First();
Object[] parameters = _instanceAndParameters.Skip(1).ToArray();
Value = (T)_method.Invoke(instance, _invokeAttributes, _binder,
parameters, _culture);
}
}
///
/// Invoked when is changed to true.
/// Implementations of this method should invoke the base class method.
///
protected override void Needed()
{
Update();
_instanceAndParameters.ItemsAdded += Update;
_instanceAndParameters.ItemsRemoved += Update;
base.Needed();
}
///
/// Invoked when is changed to false.
/// Implementations of this method should invoke the base class method.
///
protected override void NotNeeded()
{
_instanceAndParameters.ItemsAdded -= Update;
_instanceAndParameters.ItemsRemoved -= Update;
base.NotNeeded();
}
///
/// Invoked when items are added to or removed from
/// . This method just invokes
/// .
///
/// The sender of the event.
/// The instance
/// containing the event data.
void Update(object sender, ItemsEventArgs e)
{
Update();
}
///
/// The containing the
/// object on which to invoke the method or constructor. If a method is
/// static, this argument is ignored. If a constructor is static, the
/// instance contained within the must be null
/// or an instance of the class that defines the constructor.
///
readonly IValue _instance;
///
/// The method or constructor to invoke to retrieve the return value.
///
readonly MethodBase _method;
///
/// A bitmask that is a combination of 0
/// or more bit flags from . If binder is
/// null, this parameter is assigned the value
/// ; thus, whatever you pass in is
/// ignored.
///
readonly BindingFlags _invokeAttributes;
///
/// An object that enables the binding, coercion of
/// argument types, invocation of members, and retrieval of
/// objects via reflection. If binder is null,
/// the default binder is used.
///
readonly Binder _binder;
///
/// An argument list for the invoked method or
/// constructor. This is an sequence of objects with the same number,
/// order, and type as the parameters of the method or constructor to be
/// invoked. If there are no parameters, this should be null. If the
/// method or constructor represented by this instance takes a ByRef
/// parameter, there is no special attribute required for that parameter
/// in order to invoke the method or constructor using this function.
/// Any object in this array that is not explicitly initialized with a
/// value will contain the default value for that object type. For
/// reference-type elements, this value is null. For value-type elements,
/// this value is 0, 0.0, or false, depending on the specific element type.
///
readonly IEventEnumerable> _parameters;
///
/// An instance of used
/// to govern the coercion of types. If this is null, the CultureInfo
/// for the current thread is used. (This is necessary to convert a
/// that represents 1000 to a Double value, for
/// example, since 1000 is represented differently by different cultures.)
///
readonly CultureInfo _culture;
///
/// A composite of as the first instance in the
/// (if applicable) and the
/// following (if applicable).
///
readonly IEventEnumerable _instanceAndParameters;
}
}