diff --git a/LightweightIocContainer/Annotations/IocIgnoreConstructorAttribute.cs b/LightweightIocContainer/Annotations/IocIgnoreConstructorAttribute.cs new file mode 100644 index 0000000..9470dfd --- /dev/null +++ b/LightweightIocContainer/Annotations/IocIgnoreConstructorAttribute.cs @@ -0,0 +1,16 @@ +// Author: Gockner, Simon +// Created: 2022-09-01 +// Copyright(c) 2022 SimonG. All Rights Reserved. + +using LightweightIocContainer.Interfaces; + +namespace LightweightIocContainer.Annotations; + +/// +/// If a constructor is annotated with this attribute it will be ignored by the +/// +[AttributeUsage(AttributeTargets.Constructor)] +public class IocIgnoreConstructorAttribute : Attribute +{ + +} \ No newline at end of file diff --git a/LightweightIocContainer/IocContainer.cs b/LightweightIocContainer/IocContainer.cs index 2300b89..0dfa625 100644 --- a/LightweightIocContainer/IocContainer.cs +++ b/LightweightIocContainer/IocContainer.cs @@ -4,6 +4,7 @@ using System.Reflection; using System.Runtime.CompilerServices; +using LightweightIocContainer.Annotations; using LightweightIocContainer.Exceptions; using LightweightIocContainer.Interfaces; using LightweightIocContainer.Interfaces.Factories; @@ -572,7 +573,11 @@ public class IocContainer : IIocContainer, IIocResolver /// No public constructor was found for the given private List TryGetSortedConstructors(Type type) { - List sortedConstructors = type.GetConstructors().OrderByDescending(c => c.GetParameters().Length).ToList(); + List sortedConstructors = type.GetConstructors() + .Where(c => c.GetCustomAttribute() == null) + .OrderByDescending(c => c.GetParameters().Length) + .ToList(); + if (!sortedConstructors.Any()) //no public constructor available throw new NoPublicConstructorFoundException(type); diff --git a/LightweightIocContainer/LightweightIocContainer.xml b/LightweightIocContainer/LightweightIocContainer.xml index b5eb336..9fee98c 100644 --- a/LightweightIocContainer/LightweightIocContainer.xml +++ b/LightweightIocContainer/LightweightIocContainer.xml @@ -13,6 +13,11 @@ The given to convert An converted from the given + + + If a constructor is annotated with this attribute it will be ignored by the + + Helper for dynamic instance creation diff --git a/Test.LightweightIocContainer.Validation/IocValidatorTest.cs b/Test.LightweightIocContainer.Validation/IocValidatorTest.cs index b5a818b..eb1923f 100644 --- a/Test.LightweightIocContainer.Validation/IocValidatorTest.cs +++ b/Test.LightweightIocContainer.Validation/IocValidatorTest.cs @@ -4,6 +4,7 @@ using JetBrains.Annotations; using LightweightIocContainer; +using LightweightIocContainer.Annotations; using LightweightIocContainer.Exceptions; using LightweightIocContainer.Interfaces.Installers; using LightweightIocContainer.Interfaces.Registrations; @@ -21,11 +22,6 @@ public class IocValidatorTest } - public interface ITest2 - { - - } - [UsedImplicitly] public interface IParameter { @@ -36,32 +32,36 @@ public class IocValidatorTest { public Test(IParameter parameter) => parameter.Method(); } - - private class Test2 : ITest2 + + private class TestViewModel : ITest { - public Test2(ITest dependency) - { - - } - } + public TestViewModel(IParameter parameter) => parameter.Method(); + [IocIgnoreConstructor] + public TestViewModel() => throw new Exception(); + } + + private class Parameter : IParameter + { + public bool Method() => throw new NotImplementedException(); + } + [UsedImplicitly] public interface ITestFactory { ITest Create(IParameter parameter); } - + [UsedImplicitly] - public interface ITest2Factory + public interface IInvalidTestFactory { - ITest2 InvalidCreate(); - ITest2 Create(ITest test); + ITest Create(); } - + [UsedImplicitly] - public interface IInvalidFactory + public interface IParameterFactory { - ITest Create(); + IParameter Create(); } private class TestInstallerNoFactory : IIocInstaller @@ -76,18 +76,36 @@ public class IocValidatorTest private class TestInstallerWithInvalidFactory : IIocInstaller { - public void Install(IRegistrationCollector registration) => registration.Add().WithFactory(); + public void Install(IRegistrationCollector registration) => registration.Add().WithFactory(); } - - private class InvalidTestClassInstaller : IIocInstaller + + private class TestInstallerInvalidFactoryParameterRegisteredWithoutFactory : IIocInstaller { public void Install(IRegistrationCollector registration) { - registration.Add().WithFactory(); - registration.Add().WithFactory(); + registration.Add().WithFactory(); + registration.Add(); } } + private class TestInstallerInvalidFactoryParameterRegisteredWithFactory : IIocInstaller + { + public void Install(IRegistrationCollector registration) + { + registration.Add().WithFactory(); + registration.Add().WithFactory(); + } + } + + private class TestInstallerInvalidFactoryViewModel : IIocInstaller + { + public void Install(IRegistrationCollector registration) + { + registration.Add().WithFactory(); + registration.Add().WithFactory(); + } + } + [Test] public void TestValidateWithoutFactory() { @@ -129,12 +147,23 @@ public class IocValidatorTest parameterMock.Verify(p => p.Method(), Times.Never); } + + [Test] + public void TestValidateWithInvalidFactoryParameterWithoutFactory() + { + IocContainer iocContainer = new(); + iocContainer.Install(new TestInstallerInvalidFactoryParameterRegisteredWithoutFactory()); + + IocValidator validator = new(iocContainer); + + validator.Validate(); + } [Test] public void TestValidateWithInvalidParameterWithFactory() { IocContainer iocContainer = new(); - iocContainer.Install(new InvalidTestClassInstaller()); + iocContainer.Install(new TestInstallerInvalidFactoryParameterRegisteredWithFactory()); IocValidator validator = new(iocContainer); @@ -157,6 +186,31 @@ public class IocValidatorTest Assert.IsInstanceOf(iTest2CtorNotMatchingException.InnerExceptions[0]); } + + [Test] + public void TestValidateViewModelWithInvalidParameterWithFactory() + { + IocContainer iocContainer = new(); + iocContainer.Install(new TestInstallerInvalidFactoryViewModel()); + + IocValidator validator = new(iocContainer); + + AggregateException aggregateException = Assert.Throws(() => validator.Validate()); + + if (aggregateException?.InnerExceptions[0] is not NoMatchingConstructorFoundException noMatchingConstructorFoundException) + { + Assert.Fail($"First element of {nameof(aggregateException.InnerExceptions)} is not of type {nameof(NoMatchingConstructorFoundException)}."); + return; + } + + if (noMatchingConstructorFoundException.InnerExceptions[0] is not ConstructorNotMatchingException iTest2CtorNotMatchingException) + { + Assert.Fail($"First element of {nameof(noMatchingConstructorFoundException.InnerExceptions)} is not of type {nameof(ConstructorNotMatchingException)}."); + return; + } + + Assert.IsInstanceOf(iTest2CtorNotMatchingException.InnerExceptions[0]); + } [Test] public void TestValidateInvalidFactory()