Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

when publishing a delegate or class with missing dependencies, hiro will throw a ConstructorNotFound exception #2

Open
juancastrodlc opened this issue May 24, 2011 · 3 comments

Comments

@juancastrodlc
Copy link

in the sample assembly add a simple delegate

public delegate void Procedure();

Hiro attempts to find a constructor and will fail

also when adding a class to the sample assembly

public interface ISomeInterface{}

public SomeClass:ISomeInterface
{
public SomeClass(Type missingDependency){}
}

will throw the same error.

Is this by design or is it a Bug?

If it is I'm working on the patch.

Greetings.

@philiplaureano
Copy link
Owner

Hiro throws a ConstructorNotFoundException whenever a dependency is not found and this behavior is done by design. The reason why Hiro can't find a constructor on your sample Procedure delegate is that the constructor signature looks like this in IL:

.method public hidebysig specialname rtspecialname 
    instance void .ctor (
        object object,
        valuetype [mscorlib]System.IntPtr method
    ) runtime managed 

The first parameter required by the delegate has to be the target object instance, and the second parameter is the System.IntPtr pointer that points to the method that you want to execute. In this case, Hiro will automatically throw the ConstructorNotFoundException because it doesn't know how to pass in an object instance and the given method pointer. The only workaround for this issue is to tell Hiro that you want to resolve the delegate at runtime, and you can do that by using the DependencyMap.AddDeferredService() method:

var map = new DependencyMap();
yourMap.AddDeferredService();

Once you have the deferred service in place, you'll have to implement a custom IMicroContainer instance and chain it to the compiled container's NextContainer property so that Hiro will forward its request for a Procedure delegate to the next container:

var yourContainer = yourMap.CreateContainer();
yourContainer.NextContainer = new SomethingThatCanCreateProcedureDelegates();

// Use the container just like you normally would use it
var someProcedure = yourContainer.GetInstance();

@juancastrodlc
Copy link
Author

Reposting from the comment on the closed pull request:
(let's see) if I can convey how I plan to use Hiro and you can give me pointers to create some extension points:

  1. delegate declarations which will be used externally (i.e. by final user) should not be considered services, I found this problem using the source for LinqBridge and conditional compilation. When i use the bridge, Hiro tells me it has dependencies missing in the first Func and or Proc delegate declaration it finds. update: automatically registered as deffered services
  2. properties wich are primitive types, value types and strings should not be considered as dependencies (i.e. for constructor injection) or services (i.e. as injectable properties) update: I think hiro does filter valuetypes but does not filter strings
  3. if there is an actual dependency missing in some service implementations it should ignore this service as part of the compiled container do not throw exceptions, defer it to the unit test to ensure instantiation. update: register as deffered service
  4. when another map is instantiated which contains the missing dependencies, chain a new container with those dependencies.
    update: chain it to container.NextContainer
    In my fork Hiro/master branch i actually made all the unit tests pass and added these files to the SampleAssembly:
    Delegates.cs which contains one delegate declaration
    IMising.cs which contains an interface which will be implemented by an 'incomplete' service class
    SampleMissingDependency.cs which contains the implementation of the incomplete service IMissing
    and in the UnitTests project:
    BugFixes.cs added test ShouldReturnNullWhenTryingToInstantiateAnIncompleteDependency

If you add these classes without using my modifications to ConstructorResolver.cs the Delegate.cs declaration produces several errors through your unit tests including my own. (this in my opinion is an actual bug, a delegate declaration is always complete, the compiler takes care of its dependencies) Update: on thinking a bit harder a delegate is a way to have a short service (i.e. a single method interface), however could they register themselves as defferred by default? Otherwise we have to configure potentially many services by hand on each map loader, in other words conventions stops working.

I can't find how to filter missing constructor parameters without messing with the source.

@philiplaureano
Copy link
Owner

  1. You can add support for delegates by adding an IImplementation
    implementation that specifically resolves a delegate using the the
    NextContainer property. The TransientType class was built to resolve
    non-delegate types, and the reason why you're getting errors is that it
    assumes that you're using the delegate type as a regular service with
    dependencies that are available in the map, which would be incorrect in this
    case.
  2. You can solve this issue by overriding and filtering the
    GetMissingDependencies and GetRequiredDependencies methods (presumably using
    a decorator) so that they only return dependencies that are reference types.
  3. If you'll be providing the actual service implementation at runtime,
    then you can just use DependencyMap.AddDeferredService() to explicitly list
    the services that you need and then use the NextContainer property to supply
    the service instances. If you need to explicitly ignore missing dependencies
    and need to have more control over the services that need to be in the map,
    you can decorate and override the GetImplementations() method so that it
    returns the dependencies you need (including the missing dependencies).
  4. Hiro already supports DependencyMap chaining by default. For example:

var map1 = new DependencyMap();
var map2 = new DependencyMap();

var combinedMap = map1 + map2;

var combinedContainer = combinedMap.CreateContainer();

Try that out and let me know if that helps.

On Fri, May 27, 2011 at 4:54 AM, juancastrodlc <
[email protected]>wrote:

Reposting from the comment on the closed pull request:
(let's see) if I can convey how I plan to use Hiro and you can give me
pointers to create some extension points:

  1. delegate declarations which will be used externally (i.e. by final user)
    should not be considered services, I found this problem using the source for
    LinqBridge and conditional compilation. When i use the bridge, Hiro tells me
    it has dependencies missing in the first Func and or Proc delegate
    declaration it finds.
  2. properties wich are primitive types, value types and strings should not
    be considered as dependencies (i.e. for constructor injection) or services
    (i.e. as injectable properties)
  3. if there is an actual dependency missing in some service implementations
    it should ignore this service as part of the compiled container do not throw
    exceptions, defer it to the unit test to ensure instantiation.
  4. when another map is instantiated which contains the missing
    dependencies, chain a new container with those dependencies.

In my fork Hiro/master branch i actually made all the unit tests pass and
added these files to the SampleAssembly:
Delegates.cs which contains one delegate declaration
IMising.cs which contains an interface which will be implemented by an
'incomplete' service class
SampleMissingDependency.cs which contains the implementation of the
incomplete service IMissing
and in the UnitTests project:
BugFixes.cs added test
ShouldReturnNullWhenTryingToInstantiateAnIncompleteDependency

If you add these classes without using my modifications to
ConstructorResolver.cs the Delegate.cs declaration produces several errors
through your unit tests including my own. (this in my opinion is an actual
bug, a delegate declaration is always complete, the compiler takes care of
its dependencies)

I can't find how to filter missing constructor parameters without messing
with the source.

Reply to this email directly or view it on GitHub:
#2 (comment)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants