LightInject icon indicating copy to clipboard operation
LightInject copied to clipboard

InvalidCastException (PCL_111 and NET45) when resolving type with a `Func<>` in runtime arguments

Open swlasse opened this issue 9 years ago • 1 comments

InvalidCastException (PCL_111 and NET45) when resolving type with a Func<> in runtime arguments

We have some types which are registered using delegate factories. An example could be:

public Foo(long? lng1, long? lng2, string str1, string str2, Func<int, int> func = null)
{
    Lng1 = lng1;
    Lng2 = lng2;
    Str1 = str1;
    Str2 = str2;
    Func = func;
}

The type is registered like this:

var context = new IocContext();
context.RegisterObject<long?, long?, string, string, Func<int, int>, Foo>((lng1, lng2, str1, str2, func) =>
{
    return new Foo(lng1, lng2, str1, str2, func);
});

... where IocContext is an abstraction on top of LightInject:

public class IocContext
{
    ...
    public void RegisterObject<T1, T2, T3, T4, T5, TSvc>(Func<T1, T2, T3, T4, T5, TSvc> factoryFunc, string name = null)
    {
        RegisterServiceFromDelegate(typeof(TSvc), factoryFunc, name ?? typeof(TSvc).Name);
    }

    private void RegisterServiceFromDelegate(Type type, Delegate factory, string serviceName)
    {
        var serviceRegistration = new ServiceRegistration
        {
            ServiceType = type,
            FactoryExpression = factory,
            ServiceName = serviceName,
            Lifetime = null
        };
        _serviceContainer.Register(serviceRegistration);
    }
    ...
}

When resolving a registration that is given a Func<> on runtime:

Func<int, int> funcArg = x => x * 2;
var args = new object[] { 1L, 2L, "Hello1", "Hello2", funcArg };

// ----> InvalidCastException is thrown here <----
var iocFoo = context.ServiceContainer.GetInstance(typeof(Foo), typeof(Foo).Name, args) as Foo;

... we get an InvalidCastException similar to this:

System.InvalidCastException was unhandled
  HResult=-2147467262
  Message=Unable to cast object of type 'System.Int64' to type 'System.String'.
  Source=LightInject
  StackTrace:
       at DynamicMethod(Object[] )
       at LightInject.ServiceContainer.GetInstance(Type serviceType, String serviceName, Object[] arguments) in c:\Github\LightInject\src\LightInject\NuGet\tmp\Net45\Binary\LightInject\LightInject.cs:line 3049
       at LightInjectDebug.Program.Sample1() in C:\Some\Path\LightInjectDebug\LightInjectDebug\Program.cs:line 37
       at LightInjectDebug.Program.Main() in C:\Some\Path\LightInjectDebug\LightInjectDebug\Program.cs:line 19
       at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
       at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
       at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
       at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
       at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
       at System.Threading.ThreadHelper.ThreadStart()
  InnerException: 

If we remove the Func<> from the runtime arguments (and from the resolved type's ctor) everything seems to work as expected.

I have included a sample application that:

  1. Illustrates this issue
  2. Shows an "interesting" observation when all provided runtime args are null
  3. Shows a work-around (.. but is not pretty)

If you need any more context, please let me know.

Please note Again, github won't let me upload .zip files, so I have added a .txt extension to get around that bug. You know what to do :)

Environment

  • VS2015
  • Windows 8.1 Enterprise x64
  • LightInject 4.0.4 (nuget pkg)
  • .NET 4.5.2

LightInjectDebug.zip.txt

swlasse avatar Jan 18 '16 10:01 swlasse

Sorry for the late reply. Your workaround is valid and if you can live with that for now that would be great :) It's kind of a rush to get things ready for ASP.NET 5 these days :)

seesharper avatar Jan 22 '16 08:01 seesharper