1
public class MyClass : IMyClass {
    internal MyClass() {
    }
}

container.Resolve<IMyClass>();

How to configure DryIoc to use the constructor of MyClass in case when it is internal, protected or even private?

dadhi
  • 4,807
  • 19
  • 25
Maxim
  • 13,029
  • 6
  • 30
  • 45

1 Answers1

3

Specify constructor info via Made.Of:

c.Register<Something>(made:
     Made.Of(typeof(Something).GetConstructorOrNull(includeNonPublic: true,  args: argTypes));

Update:

Here is the custom implementation of constructor selector.

Couple of notes:

  • Does not support Func<..>, but support can be easily added by copying from the FactoryMethod.ConstructorWithResolvableArguments implementation
  • Will be supported by DryIoc when issue 313 is resolved

    using System;
    using System.Linq;
    using System.Reflection;
    using NUnit.Framework;
    
    namespace DryIoc.IssuesTests
    {
        [TestFixture]
        public class SO_question_How_use_implementation_with_private_constructor_in_DryIoc
        {
            public class A { internal A() { } }
            public class B { internal B(A a) { } }
    
            [Test]
            public void Test()
            {
                var c = new Container();
                c.RegisterMany(new[] {typeof(A), typeof(B)},
                    made: Made.Of(SelectMostResolvableConstructor(includeNonPublic: true)));
    
                c.Resolve<B>();
            }
    
            private FactoryMethodSelector SelectMostResolvableConstructor(bool includeNonPublic = false)
            {
                return request =>
                {
                    var implementationType = request.ImplementationType.ThrowIfNull();
                    var ctors = implementationType.GetAllConstructors(includeNonPublic: true).ToArrayOrSelf();
                    if (ctors.Length == 0)
                        return null; // Delegate handling of constructor absence to the Caller code.
                    if (ctors.Length == 1)
                        return FactoryMethod.Of(ctors[0]);
    
                    var ctorsWithMoreParamsFirst = ctors
                        .Select(c => new {Ctor = c, Params = c.GetParameters()})
                        .OrderByDescending(x => x.Params.Length);
    
                    var rules = request.Container.Rules;
                    var parameterSelector = rules.Parameters.And(request.Made.Parameters)(request);
    
                    var matchedCtor = ctorsWithMoreParamsFirst.FirstOrDefault(x =>
                            x.Params.All(p => IsResolvableParameter(p, parameterSelector, request)));
    
                    var ctor = matchedCtor.ThrowIfNull(Error.UnableToFindCtorWithAllResolvableArgs, request).Ctor;
    
                    return FactoryMethod.Of(ctor);
                };
            }
    
            private static bool IsResolvableParameter(ParameterInfo parameter,
                Func<ParameterInfo, ParameterServiceInfo> parameterSelector, Request request)
            {
                var parameterServiceInfo = parameterSelector(parameter) ?? ParameterServiceInfo.Of(parameter);
                var parameterRequest = request.Push(parameterServiceInfo.WithDetails(ServiceDetails.IfUnresolvedReturnDefault, request));
    
                if (parameterServiceInfo.Details.HasCustomValue)
                {
                    var customValue = parameterServiceInfo.Details.CustomValue;
                    return customValue == null
                        || customValue.GetType().IsAssignableTo(parameterRequest.ServiceType);
                }
    
                var parameterFactory = request.Container.ResolveFactory(parameterRequest);
                return parameterFactory != null && parameterFactory.GetExpressionOrDefault(parameterRequest) != null;
            }
        }
    }
    
dadhi
  • 4,807
  • 19
  • 25
  • OK, I hope it is possible to apply it to RegisterMany... And it is not clear where can I get argTypes in that case... it can be absolutely different.. – Maxim Aug 01 '16 at 01:08
  • Use GetSingleConstructorOrNull, it does not require args, but assume you have a single ctor. If you need automatic constructor selection based on most resolvable version, currenty it supports only public ctors: `new Container(rules => rules. With(FactoryMethod.ConstructorWithResolvableArguments)` or per – dadhi Aug 01 '16 at 02:31
  • registration `c.RegisterMany(..., made: FactoryMethod.ConstructorWithResolvableArguments)`. To en – dadhi Aug 01 '16 at 02:33
  • 1
    To enable non public constructor selection, you can write custom FactoryMethodSelector. Copy code from `ConstructorWithResolvableArguments` and modify it for all constructors. Bit tedious for now, but I'll probably add support for this in v2.7 – dadhi Aug 01 '16 at 02:37