/// <summary>
 /// Gets the resource stream.
 /// </summary>
 /// <param name="resourceLocation">The resource location.</param>
 /// <returns>A stream from which to load the resource data.</returns>
 /// <exception cref="ResourceLoaderInvalidPathException">Resource path was incorrect, or you did not set the build action to Embedded Resource</exception>
 private static Stream GetResourceStream(EmbeddedResourceAttribute resourceLocation)
 {
     return(GetResourceStream(resourceLocation.ResourcePath, resourceLocation.ContainingAssembly));
 }
        /// <summary>
        /// Loads the resource from embedded resources and returns it cast to the type of the member that the attribute decorates.
        /// </summary>
        /// <param name="targetMemberType">Type of the class member that is decorated by the attribute.</param>
        /// <param name="resourceAttribute">The attribute which describes where to find the resource.</param>
        /// <returns>Object of the requested type loaded with the data from the resource.</returns>
        /// <exception cref="ResourceLoaderInvalidTypeException">The member is of a type not supported by this library.</exception>
        /// <exception cref="ResourceLoaderException">The requested resource could not be found. Either incorrect path or not marked as embedded resource.</exception>
        private static object GetResource(Type targetMemberType, EmbeddedResourceAttribute resourceAttribute)
        {
            var resourceStream = GetResourceStream(resourceAttribute);

            // If decorated member is a string, then return the resource as string directly.
            if (targetMemberType == typeof(string))
            {
                return(GetStringResource(resourceStream));
            }

            // Check for types that can be initialized by a constructor or a given method
            foreach (var resourceLoadMethod in MethodsToCheck)
            {
                MethodBase methodToInvoke = null;
                object     instanceOfType = null;

                switch (resourceLoadMethod)
                {
                case ConstructorLoadedResource _:

                    methodToInvoke = targetMemberType.GetConstructor(
                        BindingFlags.Instance | BindingFlags.Public,
                        new ResourceLoadBinder(),
                        new[] { resourceLoadMethod.ArgumentType },
                        null);

                    break;

                case StaticMethodLoadedResource _:

                    methodToInvoke = targetMemberType.GetMethod(
                        resourceLoadMethod.MethodName,
                        BindingFlags.Static | BindingFlags.Public,
                        new ResourceLoadBinder(),
                        new[] { resourceLoadMethod.ArgumentType },
                        null);

                    break;

                case InstanceMethodLoadedResource _:

                    // Get default constructor
                    var ctor = targetMemberType.GetConstructor(
                        BindingFlags.Instance | BindingFlags.Public,
                        null,
                        Type.EmptyTypes,
                        null);

                    if (ctor != null)
                    {
                        // Create instance on which we will invoke the method and ultimately return this instance
                        instanceOfType = ctor.Invoke(null);

                        methodToInvoke = targetMemberType.GetMethod(
                            resourceLoadMethod.MethodName,
                            BindingFlags.Instance | BindingFlags.Public,
                            new ResourceLoadBinder(),
                            new[] { resourceLoadMethod.ArgumentType },
                            null);
                    }

                    break;
                }

                if (methodToInvoke != null)
                {
                    object invocationResult = null;

                    if (resourceLoadMethod.ArgumentType == typeof(Stream))
                    {
                        var args = new object[] { resourceStream };

                        invocationResult = methodToInvoke is ConstructorInfo ctor
                                               ? ctor.Invoke(args)
                                               : methodToInvoke.Invoke(instanceOfType, args);
                    }
                    else if (resourceLoadMethod.ArgumentType == typeof(StreamReader))
                    {
                        using (var sr = new StreamReader(resourceStream))
                        {
                            var args = new object[] { sr };

                            invocationResult = methodToInvoke is ConstructorInfo ctor
                                                   ? ctor.Invoke(args)
                                                   : methodToInvoke.Invoke(instanceOfType, args);
                        }
                    }
                    else if (resourceLoadMethod.ArgumentType == typeof(string))
                    {
                        var args = new[] { GetStringResource(resourceStream) };

                        invocationResult = methodToInvoke is ConstructorInfo ctor
                                               ? ctor.Invoke(args)
                                               : methodToInvoke.Invoke(instanceOfType, args);
                    }

                    return(resourceLoadMethod is InstanceMethodLoadedResource ? instanceOfType : invocationResult);
                }
            }

            // Check registered
            var plugin = RegisteredPlugins.FirstOrDefault(p => p.Type == targetMemberType);

            if (plugin != null)
            {
                return(plugin.ResourceFormat == ResourceFormat.Stream
                           ? plugin.GetObject(resourceStream)
                           : plugin.GetObject(GetStringResource(resourceStream)));
            }

            // Nothing could be found on the target type that we can populate with resource data
            throw new ResourceLoaderInvalidTypeException(targetMemberType);
        }