Skip to content

Commit ad5f9a0

Browse files
committed
Provide an API to directly call a constructor without ImmediateType (like Activator).
1 parent 8da0a5c commit ad5f9a0

File tree

4 files changed

+377
-158
lines changed

4 files changed

+377
-158
lines changed

Diff for: src/ImmediateReflection.Tests/ConstructorTestHelpers.cs

+213
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System;
22
using System.Collections.Generic;
3+
using System.Linq;
34
using JetBrains.Annotations;
45
using NUnit.Framework;
56

@@ -581,5 +582,217 @@ public static void TryNewParameterLess([NotNull, InstantHandle] TryCtor tryCtor,
581582
}
582583

583584
#endregion
585+
586+
#region New(params)/TryNew(params)
587+
588+
[NotNull, ItemNotNull]
589+
public static IEnumerable<TestCaseData> CreateNotDefaultConstructorNullParamsTestCases
590+
{
591+
[UsedImplicitly]
592+
get
593+
{
594+
yield return new TestCaseData(typeof(int), null);
595+
yield return new TestCaseData(typeof(TestStruct), null);
596+
yield return new TestCaseData(typeof(DefaultConstructor), null);
597+
yield return new TestCaseData(typeof(TemplateDefaultConstructor<int>), null);
598+
yield return new TestCaseData(typeof(ParamsOnlyConstructor), null);
599+
yield return new TestCaseData(typeof(IntParamsOnlyConstructor), null);
600+
yield return new TestCaseData(typeof(NullableIntParamsOnlyConstructor), null);
601+
yield return new TestCaseData(typeof(DefaultInheritedDefaultConstructor), null);
602+
yield return new TestCaseData(typeof(DefaultInheritedNoDefaultConstructor), null);
603+
yield return new TestCaseData(typeof(DefaultInheritedFromAbstractClass), null);
604+
yield return new TestCaseData(typeof(List<int>), null);
605+
yield return new TestCaseData(typeof(Dictionary<int, string>), null);
606+
}
607+
}
608+
609+
[NotNull, ItemNotNull]
610+
public static IEnumerable<TestCaseData> CreateNotDefaultConstructorNotNullParamsTestCases
611+
{
612+
[UsedImplicitly]
613+
get
614+
{
615+
yield return new TestCaseData(typeof(int), new object[] { });
616+
yield return new TestCaseData(typeof(TestStruct), new object[] { });
617+
yield return new TestCaseData(typeof(DefaultConstructor), new object[] { });
618+
yield return new TestCaseData(typeof(TemplateDefaultConstructor<int>), new object[] { });
619+
yield return new TestCaseData(typeof(ParamsOnlyConstructor), new object[] { });
620+
yield return new TestCaseData(typeof(IntParamsOnlyConstructor), new object[] { });
621+
yield return new TestCaseData(typeof(NullableIntParamsOnlyConstructor), new object[] { });
622+
yield return new TestCaseData(typeof(DefaultInheritedDefaultConstructor), new object[] { });
623+
yield return new TestCaseData(typeof(DefaultInheritedNoDefaultConstructor), new object[] { });
624+
yield return new TestCaseData(typeof(DefaultInheritedFromAbstractClass), new object[] { });
625+
yield return new TestCaseData(typeof(List<int>), new object[] { });
626+
yield return new TestCaseData(typeof(Dictionary<int, string>), new object[] { });
627+
628+
yield return new TestCaseData(typeof(ParameterConstructorStruct), new object[] { 12 });
629+
yield return new TestCaseData(typeof(NoDefaultConstructor), new object[] { 12 });
630+
yield return new TestCaseData(typeof(MultiParametersConstructor), new object[] { 12, 42.5f });
631+
yield return new TestCaseData(typeof(MultipleConstructors), new object[] { 12 });
632+
yield return new TestCaseData(typeof(MultipleConstructors), new object[] { 12, 42.5f });
633+
yield return new TestCaseData(typeof(TemplateNoDefaultConstructor<int>), new object[] { 12 });
634+
yield return new TestCaseData(typeof(ParamsOnlyConstructor), new object[] { 12 });
635+
yield return new TestCaseData(typeof(ParamsOnlyConstructor), new object[] { 12, 15.4f });
636+
yield return new TestCaseData(typeof(IntParamsOnlyConstructor), new object[] { 12 });
637+
yield return new TestCaseData(typeof(IntParamsOnlyConstructor), new object[] { 12, 15 });
638+
yield return new TestCaseData(typeof(NullableIntParamsOnlyConstructor), new object[] { 12, null, 25 });
639+
yield return new TestCaseData(typeof(ParamsConstructor), new object[] { 12 });
640+
yield return new TestCaseData(typeof(ParamsConstructor), new object[] { 12, 15.4f });
641+
yield return new TestCaseData(typeof(NoDefaultInheritedDefaultConstructor), new object[] { 12 });
642+
yield return new TestCaseData(typeof(NoDefaultInheritedNoDefaultConstructor), new object[] { 42 });
643+
yield return new TestCaseData(typeof(NoDefaultInheritedFromAbstractClass), new object[] { 25 });
644+
yield return new TestCaseData(typeof(int[]), new object[] { 5 });
645+
yield return new TestCaseData(typeof(List<int>), new object[] { 2 });
646+
yield return new TestCaseData(typeof(List<int>), new object[] { Enumerable.Range(0, 5) });
647+
yield return new TestCaseData(typeof(Dictionary<int, string>), new object[] { 3 });
648+
}
649+
}
650+
651+
[NotNull, ItemNotNull]
652+
public static IEnumerable<TestCaseData> CreateNotDefaultConstructorTestCases
653+
{
654+
[UsedImplicitly]
655+
get
656+
{
657+
foreach (TestCaseData testCase in CreateNotDefaultConstructorNullParamsTestCases)
658+
yield return testCase;
659+
foreach (TestCaseData testCase in CreateNotDefaultConstructorNotNullParamsTestCases)
660+
yield return testCase;
661+
}
662+
}
663+
664+
public delegate object ArgsCtor(params object[] args);
665+
666+
public static void NewWithParameters([NotNull] Type type, [NotNull, InstantHandle] ArgsCtor ctor, [CanBeNull, ItemCanBeNull] params object[] args)
667+
{
668+
object instance = ctor(args);
669+
Assert.IsNotNull(instance);
670+
Assert.AreEqual(Activator.CreateInstance(type, args), instance);
671+
}
672+
673+
[NotNull, ItemNotNull]
674+
public static IEnumerable<TestCaseData> CreateNotDefaultConstructorNoThrowNullParamsTestCases
675+
{
676+
[UsedImplicitly]
677+
get
678+
{
679+
yield return new TestCaseData(typeof(int), false, null);
680+
yield return new TestCaseData(typeof(TestStruct), false, null);
681+
yield return new TestCaseData(typeof(DefaultConstructor), false, null);
682+
yield return new TestCaseData(typeof(MultipleConstructors), false, null);
683+
yield return new TestCaseData(typeof(TemplateStruct<double>), false, null);
684+
yield return new TestCaseData(typeof(TemplateDefaultConstructor<int>), false, null);
685+
yield return new TestCaseData(typeof(ParamsOnlyConstructor), false, null);
686+
yield return new TestCaseData(typeof(IntParamsOnlyConstructor), false, null);
687+
yield return new TestCaseData(typeof(NullableIntParamsOnlyConstructor), false, null);
688+
yield return new TestCaseData(typeof(DefaultInheritedDefaultConstructor), false, null);
689+
yield return new TestCaseData(typeof(DefaultInheritedNoDefaultConstructor), false, null);
690+
yield return new TestCaseData(typeof(DefaultInheritedFromAbstractClass), false, null);
691+
yield return new TestCaseData(typeof(List<int>), false, null);
692+
yield return new TestCaseData(typeof(Dictionary<int, string>), false, null);
693+
694+
yield return new TestCaseData(typeof(NoDefaultConstructor), true, null);
695+
yield return new TestCaseData(typeof(NotAccessibleDefaultConstructor), true, null);
696+
yield return new TestCaseData(typeof(AbstractDefaultConstructor), true, null);
697+
yield return new TestCaseData(typeof(StaticClass), true, null);
698+
yield return new TestCaseData(typeof(TemplateStruct<>), true, null);
699+
yield return new TestCaseData(typeof(TemplateDefaultConstructor<>), true, null);
700+
// ReSharper disable once PossibleMistakenCallToGetType.2
701+
yield return new TestCaseData(typeof(DefaultConstructor).GetType(), true, null);
702+
yield return new TestCaseData(typeof(DefaultConstructorThrows), true, null);
703+
yield return new TestCaseData(typeof(int[]), true, null);
704+
}
705+
}
706+
707+
[NotNull, ItemNotNull]
708+
public static IEnumerable<TestCaseData> CreateNotDefaultConstructorNoThrowNotNullParamsTestCases
709+
{
710+
[UsedImplicitly]
711+
get
712+
{
713+
yield return new TestCaseData(typeof(int), false, new object[] { });
714+
yield return new TestCaseData(typeof(TestStruct), false, new object[] { });
715+
yield return new TestCaseData(typeof(DefaultConstructor), false, new object[] { });
716+
yield return new TestCaseData(typeof(MultipleConstructors), false, new object[] { });
717+
yield return new TestCaseData(typeof(MultipleConstructors), false, new object[] { 12, 12.5f });
718+
yield return new TestCaseData(typeof(TemplateStruct<double>), false, new object[] { });
719+
yield return new TestCaseData(typeof(TemplateDefaultConstructor<int>), false, new object[] { });
720+
yield return new TestCaseData(typeof(DefaultConstructorThrows), false, new object[] { 45, 51.0f });
721+
yield return new TestCaseData(typeof(ParamsOnlyConstructor), false, new object[] { });
722+
yield return new TestCaseData(typeof(ParamsOnlyConstructor), false, new object[] { 12, 45.5f });
723+
yield return new TestCaseData(typeof(IntParamsOnlyConstructor), false, new object[] { });
724+
yield return new TestCaseData(typeof(IntParamsOnlyConstructor), false, new object[] { 45, 54 });
725+
yield return new TestCaseData(typeof(NullableIntParamsOnlyConstructor), false, new object[] { });
726+
yield return new TestCaseData(typeof(NullableIntParamsOnlyConstructor), false, new object[] { 12, null, 25 });
727+
yield return new TestCaseData(typeof(DefaultInheritedDefaultConstructor), false, new object[] { });
728+
yield return new TestCaseData(typeof(DefaultInheritedNoDefaultConstructor), false, new object[] { });
729+
yield return new TestCaseData(typeof(DefaultInheritedFromAbstractClass), false, new object[] { });
730+
yield return new TestCaseData(typeof(NoDefaultInheritedDefaultConstructor), false, new object[] { 12 });
731+
yield return new TestCaseData(typeof(NoDefaultInheritedNoDefaultConstructor), false, new object[] { 42 });
732+
yield return new TestCaseData(typeof(NoDefaultInheritedFromAbstractClass), false, new object[] { 25 });
733+
yield return new TestCaseData(typeof(int[]), false, new object[] { 5 });
734+
yield return new TestCaseData(typeof(List<int>), false, new object[] { });
735+
yield return new TestCaseData(typeof(List<int>), false, new object[] { 2 });
736+
yield return new TestCaseData(typeof(List<int>), false, new object[] { Enumerable.Range(0, 5) });
737+
yield return new TestCaseData(typeof(Dictionary<int, string>), false, new object[] { });
738+
yield return new TestCaseData(typeof(Dictionary<int, string>), false, new object[] { 3 });
739+
740+
yield return new TestCaseData(typeof(int), true, new object[] { 12 });
741+
yield return new TestCaseData(typeof(TestStruct), true, new object[] { 12 });
742+
yield return new TestCaseData(typeof(DefaultConstructor), true, new object[] { 12 });
743+
yield return new TestCaseData(typeof(MultipleConstructors), true, new object[] { 12.5f, 12 });
744+
yield return new TestCaseData(typeof(TemplateStruct<double>), true, new object[] { 25 });
745+
yield return new TestCaseData(typeof(TemplateDefaultConstructor<int>), true, new object[] { 25 });
746+
yield return new TestCaseData(typeof(NoDefaultConstructor), true, new object[] { });
747+
yield return new TestCaseData(typeof(NotAccessibleDefaultConstructor), true, new object[] { });
748+
yield return new TestCaseData(typeof(AbstractDefaultConstructor), true, new object[] { });
749+
yield return new TestCaseData(typeof(StaticClass), true, new object[] { });
750+
yield return new TestCaseData(typeof(TemplateStruct<>), true, new object[] { });
751+
yield return new TestCaseData(typeof(TemplateDefaultConstructor<>), true, new object[] { });
752+
yield return new TestCaseData(typeof(DefaultInheritedDefaultConstructor), true, new object[] { 45 });
753+
yield return new TestCaseData(typeof(DefaultInheritedNoDefaultConstructor), true, new object[] { 51 });
754+
yield return new TestCaseData(typeof(DefaultInheritedFromAbstractClass), true, new object[] { 72 });
755+
yield return new TestCaseData(typeof(NoDefaultInheritedDefaultConstructor), true, new object[] { 45, 35 });
756+
yield return new TestCaseData(typeof(NoDefaultInheritedNoDefaultConstructor), true, new object[] { 51, 25 });
757+
yield return new TestCaseData(typeof(NoDefaultInheritedFromAbstractClass), true, new object[] { 72, 15 });
758+
// ReSharper disable once PossibleMistakenCallToGetType.2
759+
yield return new TestCaseData(typeof(DefaultConstructor).GetType(), true, new object[] { });
760+
yield return new TestCaseData(typeof(DefaultConstructorThrows), true, new object[] { });
761+
yield return new TestCaseData(typeof(DefaultConstructorThrows), true, new object[] { 12 });
762+
yield return new TestCaseData(typeof(int[]), true, new object[] { });
763+
}
764+
}
765+
766+
[NotNull, ItemNotNull]
767+
public static IEnumerable<TestCaseData> CreateNotDefaultConstructorNoThrowTestCases
768+
{
769+
[UsedImplicitly]
770+
get
771+
{
772+
foreach (TestCaseData testCase in CreateNotDefaultConstructorNoThrowNullParamsTestCases)
773+
yield return testCase;
774+
foreach (TestCaseData testCase in CreateNotDefaultConstructorNoThrowNotNullParamsTestCases)
775+
yield return testCase;
776+
}
777+
}
778+
779+
public delegate bool TryArgsCtor(out object instance, out Exception exception, params object[] args);
780+
781+
public static void TryNewWithParameters([NotNull] Type type, bool expectFail, [NotNull, InstantHandle] TryArgsCtor tryCtor, [CanBeNull, ItemCanBeNull] params object[] args)
782+
{
783+
Assert.AreEqual(!expectFail, tryCtor(out object instance, out Exception ex, args));
784+
if (expectFail)
785+
{
786+
Assert.IsNull(instance);
787+
Assert.IsNotNull(ex);
788+
}
789+
else
790+
{
791+
Assert.IsNotNull(instance);
792+
Assert.AreEqual(Activator.CreateInstance(type, args), instance);
793+
}
794+
}
795+
796+
#endregion
584797
}
585798
}

Diff for: src/ImmediateReflection.Tests/Extensions/TypeExtensionsTests.cs

+58
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ namespace ImmediateReflection.Tests
1414
[TestFixture]
1515
internal class TypeExtensionsTests : ImmediateReflectionTestsBase
1616
{
17+
#region New/TryNew
18+
1719
[TestCaseSource(typeof(ConstructorTestHelpers), nameof(CreateDefaultConstructorTestCases))]
1820
public void NewParameterLess([NotNull] Type type)
1921
{
@@ -94,6 +96,62 @@ public void TryNewParameterLess_Throws()
9496
// ReSharper disable once AssignNullToNotNullAttribute
9597
Assert.Throws<ArgumentNullException>(() => TypeExtensions.TryNew(null, out _, out _));
9698
}
99+
100+
#endregion
101+
102+
#region New(params)/TryNew(params)
103+
104+
[TestCaseSource(typeof(ConstructorTestHelpers), nameof(CreateNotDefaultConstructorNotNullParamsTestCases))]
105+
public void NewWithParameters([NotNull] Type type, [CanBeNull, ItemCanBeNull] params object[] arguments)
106+
{
107+
ConstructorTestHelpers.NewWithParameters(
108+
type,
109+
args => TypeExtensions.New(type, args),
110+
arguments);
111+
}
112+
113+
[Test]
114+
public void NewWithParameters_Throws()
115+
{
116+
// ReSharper disable ReturnValueOfPureMethodIsNotUsed
117+
// ReSharper disable AssignNullToNotNullAttribute
118+
Assert.Throws<ArgumentNullException>(() => TypeExtensions.New(null, 12));
119+
Assert.Throws<ArgumentNullException>(() => TypeExtensions.New(typeof(ParamsConstructor), null));
120+
Assert.Throws<ArgumentNullException>(() => TypeExtensions.New(null, null));
121+
// ReSharper restore AssignNullToNotNullAttribute
122+
123+
Assert.Throws<MissingMethodException>(() => TypeExtensions.New(typeof(NoDefaultConstructor), 12, 42));
124+
Assert.Throws<MissingMethodException>(() => TypeExtensions.New(typeof(NotAccessibleConstructor), 12));
125+
Assert.Throws<MissingMethodException>(() => TypeExtensions.New(typeof(MultiParametersConstructor), 12f, 12));
126+
Assert.Throws<MissingMethodException>(() => TypeExtensions.New(typeof(ParamsConstructor), 12f, 12));
127+
Assert.Throws<MissingMethodException>(() => TypeExtensions.New(typeof(NoDefaultInheritedDefaultConstructor), 12f));
128+
Assert.Throws<MemberAccessException>(() => TypeExtensions.New(typeof(AbstractNoConstructor), 12));
129+
Assert.Throws<ArgumentException>(() => TypeExtensions.New(typeof(TemplateNoDefaultConstructor<>), 12));
130+
Assert.Throws<TargetInvocationException>(() => TypeExtensions.New(typeof(NotDefaultConstructorThrows), 12));
131+
// ReSharper restore ReturnValueOfPureMethodIsNotUsed
132+
}
133+
134+
[TestCaseSource(typeof(ConstructorTestHelpers), nameof(CreateNotDefaultConstructorNoThrowNotNullParamsTestCases))]
135+
public void TryNewWithParameters([NotNull] Type type, bool expectFail, [CanBeNull, ItemCanBeNull] params object[] arguments)
136+
{
137+
ConstructorTestHelpers.TryNewWithParameters(
138+
type,
139+
expectFail,
140+
(out object instance, out Exception exception, object[] args) => TypeExtensions.TryNew(type, out instance, out exception, args),
141+
arguments);
142+
}
143+
144+
[Test]
145+
public void TryNewWithParameters_Throws()
146+
{
147+
// ReSharper disable AssignNullToNotNullAttribute
148+
Assert.Throws<ArgumentNullException>(() => TypeExtensions.TryNew(null, out _, out _, 12));
149+
Assert.Throws<ArgumentNullException>(() => TypeExtensions.TryNew(typeof(ParamsConstructor), out _, out _, null));
150+
Assert.Throws<ArgumentNullException>(() => TypeExtensions.TryNew(null, out _, out _, null));
151+
// ReSharper restore AssignNullToNotNullAttribute
152+
}
153+
154+
#endregion
97155
}
98156
}
99157
#endif

0 commit comments

Comments
 (0)