/// <summary>
        /// Initializes a new instance of the <see cref="DelegateTarget" /> class.
        /// </summary>
        /// <param name="factory">Required - the factory delegate.  Must have a return type and can take
        /// 0 or more parameters.</param>
        /// <param name="declaredType">Optional - type that will be set into the <see cref="DeclaredType" /> for the target;
        /// if not provided, then it will be derived from the <paramref name="factory" />'s return type</param>
        /// <param name="scopeBehaviour">Scope behaviour for this delegate.  The default is <see cref="ScopeBehaviour.Implicit"/>, which means
        /// that that any returned instance will be tracked implicitly by the active scope.  If the delegate produces a new instance, then
        /// this or <see cref="ScopeBehaviour.Explicit"/> can be used safely - the choice being whether
        /// the expression should produce one instance per scope, or should act as a disposable transient object.</param>
        /// <param name="scopePreference">If <paramref name="scopeBehaviour"/> is not <see cref="ScopeBehaviour.None"/>, then this controls
        /// the preferred scope for the instance to be tracked.  Defaults to <see cref="ScopePreference.Current"/></param>
        /// <exception cref="ArgumentException">If the <paramref name="factory" /> represents a void delegate or if
        /// <paramref name="declaredType" /> is passed but the type is not compatible with the return type of
        /// <paramref name="factory" />.</exception>
        /// <exception cref="ArgumentNullException">If <paramref name="factory" /> is null</exception>
        public DelegateTarget(
            Delegate factory,
            Type declaredType               = null,
            ScopeBehaviour scopeBehaviour   = ScopeBehaviour.Implicit,
            ScopePreference scopePreference = ScopePreference.Current)
        {
            if (factory == null)
            {
                throw new ArgumentNullException(nameof(factory));
            }

            FactoryMethod = factory.GetMethodInfo();

            if (FactoryMethod.ReturnType == typeof(void))
            {
                throw new ArgumentException("Factory must have a return type", nameof(factory));
            }
            if (FactoryMethod.GetParameters().Any(p => p.ParameterType.IsByRef))
            {
                throw new ArgumentException("Delegates which have ref or out parameters are not permitted as the factory argument", nameof(factory));
            }

            if (declaredType != null)
            {
                if (!TypeHelpers.AreCompatible(FactoryMethod.ReturnType, declaredType) && !TypeHelpers.AreCompatible(declaredType, FactoryMethod.ReturnType))
                {
                    throw new ArgumentException(string.Format(ExceptionResources.DeclaredTypeIsNotCompatible_Format, declaredType, FactoryMethod.ReturnType), nameof(declaredType));
                }
            }

            this._declaredType    = declaredType;
            this._scopeBehaviour  = scopeBehaviour;
            this._scopePreference = scopePreference;
            Factory = factory;
        }
        public NullaryDelegateTarget(
            Delegate factory,
            Type declaredType               = null,
            ScopeBehaviour scopeBehaviour   = ScopeBehaviour.Implicit,
            ScopePreference scopePreference = ScopePreference.Current)
            : base(factory, declaredType, scopeBehaviour, scopePreference)
        {
            if (FactoryMethod.GetParameters()?.Length > 0)
            {
                throw new ArgumentException("Only nullary delegates (i.e. which have no parameters) can be used for this target");
            }

            this._strongDelegate = Expression.Lambda <Func <object> >(Expression.Convert(
                                                                          Expression.Invoke(Expression.Constant(factory)), typeof(object))).Compile();
        }