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; } }