diff --git a/src/ImmediateReflection.Tests/ConstructorTestHelpers.cs b/src/ImmediateReflection.Tests/ConstructorTestHelpers.cs index a9a61f6..1fb4bb9 100644 --- a/src/ImmediateReflection.Tests/ConstructorTestHelpers.cs +++ b/src/ImmediateReflection.Tests/ConstructorTestHelpers.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq; using JetBrains.Annotations; using NUnit.Framework; @@ -581,5 +582,217 @@ public static void TryNewParameterLess([NotNull, InstantHandle] TryCtor tryCtor, } #endregion + + #region New(params)/TryNew(params) + + [NotNull, ItemNotNull] + public static IEnumerable CreateNotDefaultConstructorNullParamsTestCases + { + [UsedImplicitly] + get + { + yield return new TestCaseData(typeof(int), null); + yield return new TestCaseData(typeof(TestStruct), null); + yield return new TestCaseData(typeof(DefaultConstructor), null); + yield return new TestCaseData(typeof(TemplateDefaultConstructor), null); + yield return new TestCaseData(typeof(ParamsOnlyConstructor), null); + yield return new TestCaseData(typeof(IntParamsOnlyConstructor), null); + yield return new TestCaseData(typeof(NullableIntParamsOnlyConstructor), null); + yield return new TestCaseData(typeof(DefaultInheritedDefaultConstructor), null); + yield return new TestCaseData(typeof(DefaultInheritedNoDefaultConstructor), null); + yield return new TestCaseData(typeof(DefaultInheritedFromAbstractClass), null); + yield return new TestCaseData(typeof(List), null); + yield return new TestCaseData(typeof(Dictionary), null); + } + } + + [NotNull, ItemNotNull] + public static IEnumerable CreateNotDefaultConstructorNotNullParamsTestCases + { + [UsedImplicitly] + get + { + yield return new TestCaseData(typeof(int), new object[] { }); + yield return new TestCaseData(typeof(TestStruct), new object[] { }); + yield return new TestCaseData(typeof(DefaultConstructor), new object[] { }); + yield return new TestCaseData(typeof(TemplateDefaultConstructor), new object[] { }); + yield return new TestCaseData(typeof(ParamsOnlyConstructor), new object[] { }); + yield return new TestCaseData(typeof(IntParamsOnlyConstructor), new object[] { }); + yield return new TestCaseData(typeof(NullableIntParamsOnlyConstructor), new object[] { }); + yield return new TestCaseData(typeof(DefaultInheritedDefaultConstructor), new object[] { }); + yield return new TestCaseData(typeof(DefaultInheritedNoDefaultConstructor), new object[] { }); + yield return new TestCaseData(typeof(DefaultInheritedFromAbstractClass), new object[] { }); + yield return new TestCaseData(typeof(List), new object[] { }); + yield return new TestCaseData(typeof(Dictionary), new object[] { }); + + yield return new TestCaseData(typeof(ParameterConstructorStruct), new object[] { 12 }); + yield return new TestCaseData(typeof(NoDefaultConstructor), new object[] { 12 }); + yield return new TestCaseData(typeof(MultiParametersConstructor), new object[] { 12, 42.5f }); + yield return new TestCaseData(typeof(MultipleConstructors), new object[] { 12 }); + yield return new TestCaseData(typeof(MultipleConstructors), new object[] { 12, 42.5f }); + yield return new TestCaseData(typeof(TemplateNoDefaultConstructor), new object[] { 12 }); + yield return new TestCaseData(typeof(ParamsOnlyConstructor), new object[] { 12 }); + yield return new TestCaseData(typeof(ParamsOnlyConstructor), new object[] { 12, 15.4f }); + yield return new TestCaseData(typeof(IntParamsOnlyConstructor), new object[] { 12 }); + yield return new TestCaseData(typeof(IntParamsOnlyConstructor), new object[] { 12, 15 }); + yield return new TestCaseData(typeof(NullableIntParamsOnlyConstructor), new object[] { 12, null, 25 }); + yield return new TestCaseData(typeof(ParamsConstructor), new object[] { 12 }); + yield return new TestCaseData(typeof(ParamsConstructor), new object[] { 12, 15.4f }); + yield return new TestCaseData(typeof(NoDefaultInheritedDefaultConstructor), new object[] { 12 }); + yield return new TestCaseData(typeof(NoDefaultInheritedNoDefaultConstructor), new object[] { 42 }); + yield return new TestCaseData(typeof(NoDefaultInheritedFromAbstractClass), new object[] { 25 }); + yield return new TestCaseData(typeof(int[]), new object[] { 5 }); + yield return new TestCaseData(typeof(List), new object[] { 2 }); + yield return new TestCaseData(typeof(List), new object[] { Enumerable.Range(0, 5) }); + yield return new TestCaseData(typeof(Dictionary), new object[] { 3 }); + } + } + + [NotNull, ItemNotNull] + public static IEnumerable CreateNotDefaultConstructorTestCases + { + [UsedImplicitly] + get + { + foreach (TestCaseData testCase in CreateNotDefaultConstructorNullParamsTestCases) + yield return testCase; + foreach (TestCaseData testCase in CreateNotDefaultConstructorNotNullParamsTestCases) + yield return testCase; + } + } + + public delegate object ArgsCtor(params object[] args); + + public static void NewWithParameters([NotNull] Type type, [NotNull, InstantHandle] ArgsCtor ctor, [CanBeNull, ItemCanBeNull] params object[] args) + { + object instance = ctor(args); + Assert.IsNotNull(instance); + Assert.AreEqual(Activator.CreateInstance(type, args), instance); + } + + [NotNull, ItemNotNull] + public static IEnumerable CreateNotDefaultConstructorNoThrowNullParamsTestCases + { + [UsedImplicitly] + get + { + yield return new TestCaseData(typeof(int), false, null); + yield return new TestCaseData(typeof(TestStruct), false, null); + yield return new TestCaseData(typeof(DefaultConstructor), false, null); + yield return new TestCaseData(typeof(MultipleConstructors), false, null); + yield return new TestCaseData(typeof(TemplateStruct), false, null); + yield return new TestCaseData(typeof(TemplateDefaultConstructor), false, null); + yield return new TestCaseData(typeof(ParamsOnlyConstructor), false, null); + yield return new TestCaseData(typeof(IntParamsOnlyConstructor), false, null); + yield return new TestCaseData(typeof(NullableIntParamsOnlyConstructor), false, null); + yield return new TestCaseData(typeof(DefaultInheritedDefaultConstructor), false, null); + yield return new TestCaseData(typeof(DefaultInheritedNoDefaultConstructor), false, null); + yield return new TestCaseData(typeof(DefaultInheritedFromAbstractClass), false, null); + yield return new TestCaseData(typeof(List), false, null); + yield return new TestCaseData(typeof(Dictionary), false, null); + + yield return new TestCaseData(typeof(NoDefaultConstructor), true, null); + yield return new TestCaseData(typeof(NotAccessibleDefaultConstructor), true, null); + yield return new TestCaseData(typeof(AbstractDefaultConstructor), true, null); + yield return new TestCaseData(typeof(StaticClass), true, null); + yield return new TestCaseData(typeof(TemplateStruct<>), true, null); + yield return new TestCaseData(typeof(TemplateDefaultConstructor<>), true, null); + // ReSharper disable once PossibleMistakenCallToGetType.2 + yield return new TestCaseData(typeof(DefaultConstructor).GetType(), true, null); + yield return new TestCaseData(typeof(DefaultConstructorThrows), true, null); + yield return new TestCaseData(typeof(int[]), true, null); + } + } + + [NotNull, ItemNotNull] + public static IEnumerable CreateNotDefaultConstructorNoThrowNotNullParamsTestCases + { + [UsedImplicitly] + get + { + yield return new TestCaseData(typeof(int), false, new object[] { }); + yield return new TestCaseData(typeof(TestStruct), false, new object[] { }); + yield return new TestCaseData(typeof(DefaultConstructor), false, new object[] { }); + yield return new TestCaseData(typeof(MultipleConstructors), false, new object[] { }); + yield return new TestCaseData(typeof(MultipleConstructors), false, new object[] { 12, 12.5f }); + yield return new TestCaseData(typeof(TemplateStruct), false, new object[] { }); + yield return new TestCaseData(typeof(TemplateDefaultConstructor), false, new object[] { }); + yield return new TestCaseData(typeof(DefaultConstructorThrows), false, new object[] { 45, 51.0f }); + yield return new TestCaseData(typeof(ParamsOnlyConstructor), false, new object[] { }); + yield return new TestCaseData(typeof(ParamsOnlyConstructor), false, new object[] { 12, 45.5f }); + yield return new TestCaseData(typeof(IntParamsOnlyConstructor), false, new object[] { }); + yield return new TestCaseData(typeof(IntParamsOnlyConstructor), false, new object[] { 45, 54 }); + yield return new TestCaseData(typeof(NullableIntParamsOnlyConstructor), false, new object[] { }); + yield return new TestCaseData(typeof(NullableIntParamsOnlyConstructor), false, new object[] { 12, null, 25 }); + yield return new TestCaseData(typeof(DefaultInheritedDefaultConstructor), false, new object[] { }); + yield return new TestCaseData(typeof(DefaultInheritedNoDefaultConstructor), false, new object[] { }); + yield return new TestCaseData(typeof(DefaultInheritedFromAbstractClass), false, new object[] { }); + yield return new TestCaseData(typeof(NoDefaultInheritedDefaultConstructor), false, new object[] { 12 }); + yield return new TestCaseData(typeof(NoDefaultInheritedNoDefaultConstructor), false, new object[] { 42 }); + yield return new TestCaseData(typeof(NoDefaultInheritedFromAbstractClass), false, new object[] { 25 }); + yield return new TestCaseData(typeof(int[]), false, new object[] { 5 }); + yield return new TestCaseData(typeof(List), false, new object[] { }); + yield return new TestCaseData(typeof(List), false, new object[] { 2 }); + yield return new TestCaseData(typeof(List), false, new object[] { Enumerable.Range(0, 5) }); + yield return new TestCaseData(typeof(Dictionary), false, new object[] { }); + yield return new TestCaseData(typeof(Dictionary), false, new object[] { 3 }); + + yield return new TestCaseData(typeof(int), true, new object[] { 12 }); + yield return new TestCaseData(typeof(TestStruct), true, new object[] { 12 }); + yield return new TestCaseData(typeof(DefaultConstructor), true, new object[] { 12 }); + yield return new TestCaseData(typeof(MultipleConstructors), true, new object[] { 12.5f, 12 }); + yield return new TestCaseData(typeof(TemplateStruct), true, new object[] { 25 }); + yield return new TestCaseData(typeof(TemplateDefaultConstructor), true, new object[] { 25 }); + yield return new TestCaseData(typeof(NoDefaultConstructor), true, new object[] { }); + yield return new TestCaseData(typeof(NotAccessibleDefaultConstructor), true, new object[] { }); + yield return new TestCaseData(typeof(AbstractDefaultConstructor), true, new object[] { }); + yield return new TestCaseData(typeof(StaticClass), true, new object[] { }); + yield return new TestCaseData(typeof(TemplateStruct<>), true, new object[] { }); + yield return new TestCaseData(typeof(TemplateDefaultConstructor<>), true, new object[] { }); + yield return new TestCaseData(typeof(DefaultInheritedDefaultConstructor), true, new object[] { 45 }); + yield return new TestCaseData(typeof(DefaultInheritedNoDefaultConstructor), true, new object[] { 51 }); + yield return new TestCaseData(typeof(DefaultInheritedFromAbstractClass), true, new object[] { 72 }); + yield return new TestCaseData(typeof(NoDefaultInheritedDefaultConstructor), true, new object[] { 45, 35 }); + yield return new TestCaseData(typeof(NoDefaultInheritedNoDefaultConstructor), true, new object[] { 51, 25 }); + yield return new TestCaseData(typeof(NoDefaultInheritedFromAbstractClass), true, new object[] { 72, 15 }); + // ReSharper disable once PossibleMistakenCallToGetType.2 + yield return new TestCaseData(typeof(DefaultConstructor).GetType(), true, new object[] { }); + yield return new TestCaseData(typeof(DefaultConstructorThrows), true, new object[] { }); + yield return new TestCaseData(typeof(DefaultConstructorThrows), true, new object[] { 12 }); + yield return new TestCaseData(typeof(int[]), true, new object[] { }); + } + } + + [NotNull, ItemNotNull] + public static IEnumerable CreateNotDefaultConstructorNoThrowTestCases + { + [UsedImplicitly] + get + { + foreach (TestCaseData testCase in CreateNotDefaultConstructorNoThrowNullParamsTestCases) + yield return testCase; + foreach (TestCaseData testCase in CreateNotDefaultConstructorNoThrowNotNullParamsTestCases) + yield return testCase; + } + } + + public delegate bool TryArgsCtor(out object instance, out Exception exception, params object[] args); + + public static void TryNewWithParameters([NotNull] Type type, bool expectFail, [NotNull, InstantHandle] TryArgsCtor tryCtor, [CanBeNull, ItemCanBeNull] params object[] args) + { + Assert.AreEqual(!expectFail, tryCtor(out object instance, out Exception ex, args)); + if (expectFail) + { + Assert.IsNull(instance); + Assert.IsNotNull(ex); + } + else + { + Assert.IsNotNull(instance); + Assert.AreEqual(Activator.CreateInstance(type, args), instance); + } + } + + #endregion } } \ No newline at end of file diff --git a/src/ImmediateReflection.Tests/Extensions/TypeExtensionsTests.cs b/src/ImmediateReflection.Tests/Extensions/TypeExtensionsTests.cs index 7bace3b..12d57c8 100644 --- a/src/ImmediateReflection.Tests/Extensions/TypeExtensionsTests.cs +++ b/src/ImmediateReflection.Tests/Extensions/TypeExtensionsTests.cs @@ -14,6 +14,8 @@ namespace ImmediateReflection.Tests [TestFixture] internal class TypeExtensionsTests : ImmediateReflectionTestsBase { + #region New/TryNew + [TestCaseSource(typeof(ConstructorTestHelpers), nameof(CreateDefaultConstructorTestCases))] public void NewParameterLess([NotNull] Type type) { @@ -94,6 +96,62 @@ public void TryNewParameterLess_Throws() // ReSharper disable once AssignNullToNotNullAttribute Assert.Throws(() => TypeExtensions.TryNew(null, out _, out _)); } + + #endregion + + #region New(params)/TryNew(params) + + [TestCaseSource(typeof(ConstructorTestHelpers), nameof(CreateNotDefaultConstructorNotNullParamsTestCases))] + public void NewWithParameters([NotNull] Type type, [CanBeNull, ItemCanBeNull] params object[] arguments) + { + ConstructorTestHelpers.NewWithParameters( + type, + args => TypeExtensions.New(type, args), + arguments); + } + + [Test] + public void NewWithParameters_Throws() + { + // ReSharper disable ReturnValueOfPureMethodIsNotUsed + // ReSharper disable AssignNullToNotNullAttribute + Assert.Throws(() => TypeExtensions.New(null, 12)); + Assert.Throws(() => TypeExtensions.New(typeof(ParamsConstructor), null)); + Assert.Throws(() => TypeExtensions.New(null, null)); + // ReSharper restore AssignNullToNotNullAttribute + + Assert.Throws(() => TypeExtensions.New(typeof(NoDefaultConstructor), 12, 42)); + Assert.Throws(() => TypeExtensions.New(typeof(NotAccessibleConstructor), 12)); + Assert.Throws(() => TypeExtensions.New(typeof(MultiParametersConstructor), 12f, 12)); + Assert.Throws(() => TypeExtensions.New(typeof(ParamsConstructor), 12f, 12)); + Assert.Throws(() => TypeExtensions.New(typeof(NoDefaultInheritedDefaultConstructor), 12f)); + Assert.Throws(() => TypeExtensions.New(typeof(AbstractNoConstructor), 12)); + Assert.Throws(() => TypeExtensions.New(typeof(TemplateNoDefaultConstructor<>), 12)); + Assert.Throws(() => TypeExtensions.New(typeof(NotDefaultConstructorThrows), 12)); + // ReSharper restore ReturnValueOfPureMethodIsNotUsed + } + + [TestCaseSource(typeof(ConstructorTestHelpers), nameof(CreateNotDefaultConstructorNoThrowNotNullParamsTestCases))] + public void TryNewWithParameters([NotNull] Type type, bool expectFail, [CanBeNull, ItemCanBeNull] params object[] arguments) + { + ConstructorTestHelpers.TryNewWithParameters( + type, + expectFail, + (out object instance, out Exception exception, object[] args) => TypeExtensions.TryNew(type, out instance, out exception, args), + arguments); + } + + [Test] + public void TryNewWithParameters_Throws() + { + // ReSharper disable AssignNullToNotNullAttribute + Assert.Throws(() => TypeExtensions.TryNew(null, out _, out _, 12)); + Assert.Throws(() => TypeExtensions.TryNew(typeof(ParamsConstructor), out _, out _, null)); + Assert.Throws(() => TypeExtensions.TryNew(null, out _, out _, null)); + // ReSharper restore AssignNullToNotNullAttribute + } + + #endregion } } #endif \ No newline at end of file diff --git a/src/ImmediateReflection.Tests/ImmediateTypeTests.cs b/src/ImmediateReflection.Tests/ImmediateTypeTests.cs index 3dc13a9..de291e4 100644 --- a/src/ImmediateReflection.Tests/ImmediateTypeTests.cs +++ b/src/ImmediateReflection.Tests/ImmediateTypeTests.cs @@ -720,68 +720,17 @@ public void TryNewParameterLess() #region New(params)/TryNew(params) - private static IEnumerable CreateNotDefaultConstructorTestCases + [TestCaseSource(typeof(ConstructorTestHelpers), nameof(CreateNotDefaultConstructorTestCases))] + public void NewWithParameters([NotNull] Type type, [CanBeNull, ItemCanBeNull] params object[] arguments) { - [UsedImplicitly] - get - { - yield return new TestCaseData(typeof(int), null); - yield return new TestCaseData(typeof(int), new object[] { }); - yield return new TestCaseData(typeof(TestStruct), null); - yield return new TestCaseData(typeof(TestStruct), new object[] { }); - yield return new TestCaseData(typeof(DefaultConstructor), null); - yield return new TestCaseData(typeof(DefaultConstructor), new object[] { }); - yield return new TestCaseData(typeof(TemplateDefaultConstructor), null); - yield return new TestCaseData(typeof(TemplateDefaultConstructor), new object[] { }); - yield return new TestCaseData(typeof(ParamsOnlyConstructor), null); - yield return new TestCaseData(typeof(ParamsOnlyConstructor), new object[] { }); - yield return new TestCaseData(typeof(IntParamsOnlyConstructor), null); - yield return new TestCaseData(typeof(IntParamsOnlyConstructor), new object[] { }); - yield return new TestCaseData(typeof(NullableIntParamsOnlyConstructor), null); - yield return new TestCaseData(typeof(NullableIntParamsOnlyConstructor), new object[] { }); - yield return new TestCaseData(typeof(DefaultInheritedDefaultConstructor), null); - yield return new TestCaseData(typeof(DefaultInheritedDefaultConstructor), new object[] { }); - yield return new TestCaseData(typeof(DefaultInheritedNoDefaultConstructor), null); - yield return new TestCaseData(typeof(DefaultInheritedNoDefaultConstructor), new object[] { }); - yield return new TestCaseData(typeof(DefaultInheritedFromAbstractClass), null); - yield return new TestCaseData(typeof(DefaultInheritedFromAbstractClass), new object[] { }); - yield return new TestCaseData(typeof(List), null); - yield return new TestCaseData(typeof(List), new object[] { }); - yield return new TestCaseData(typeof(Dictionary), null); - yield return new TestCaseData(typeof(Dictionary), new object[] { }); - - yield return new TestCaseData(typeof(ParameterConstructorStruct), new object[] { 12 }); - yield return new TestCaseData(typeof(NoDefaultConstructor), new object[] { 12 }); - yield return new TestCaseData(typeof(MultiParametersConstructor), new object[] { 12, 42.5f }); - yield return new TestCaseData(typeof(MultipleConstructors), new object[] { 12 }); - yield return new TestCaseData(typeof(MultipleConstructors), new object[] { 12, 42.5f }); - yield return new TestCaseData(typeof(TemplateNoDefaultConstructor), new object[] { 12 }); - yield return new TestCaseData(typeof(ParamsOnlyConstructor), new object[] { 12 }); - yield return new TestCaseData(typeof(ParamsOnlyConstructor), new object[] { 12, 15.4f }); - yield return new TestCaseData(typeof(IntParamsOnlyConstructor), new object[] { 12 }); - yield return new TestCaseData(typeof(IntParamsOnlyConstructor), new object[] { 12, 15 }); - yield return new TestCaseData(typeof(NullableIntParamsOnlyConstructor), null); - yield return new TestCaseData(typeof(NullableIntParamsOnlyConstructor), new object[] { 12, null, 25 }); - yield return new TestCaseData(typeof(ParamsConstructor), new object[] { 12 }); - yield return new TestCaseData(typeof(ParamsConstructor), new object[] { 12, 15.4f }); - yield return new TestCaseData(typeof(NoDefaultInheritedDefaultConstructor), new object[] { 12 }); - yield return new TestCaseData(typeof(NoDefaultInheritedNoDefaultConstructor), new object[] { 42 }); - yield return new TestCaseData(typeof(NoDefaultInheritedFromAbstractClass), new object[] { 25 }); - yield return new TestCaseData(typeof(int[]), new object[] { 5 }); - yield return new TestCaseData(typeof(List), new object[] { 2 }); - yield return new TestCaseData(typeof(List), new object[] { Enumerable.Range(0, 5) }); - yield return new TestCaseData(typeof(Dictionary), new object[] { 3 }); - } - } - - [TestCaseSource(nameof(CreateNotDefaultConstructorTestCases))] - public void NewWithParameters([NotNull] Type type, [CanBeNull, ItemCanBeNull] params object[] args) - { - var immediateType = new ImmediateType(type); - - object instance = immediateType.New(args); - Assert.IsNotNull(instance); - Assert.AreEqual(Activator.CreateInstance(type, args), instance); + ConstructorTestHelpers.NewWithParameters( + type, + args => + { + var immediateType = new ImmediateType(type); + return immediateType.New(args); + }, + arguments); } [Test] @@ -811,106 +760,21 @@ public void NewWithParameters_Throws() immediateType = new ImmediateType(typeof(NotDefaultConstructorThrows)); Assert.Throws(() => immediateType.New(12)); + // ReSharper restore ReturnValueOfPureMethodIsNotUsed } - private static IEnumerable CreateNotDefaultConstructorNoThrowTestCases - { - [UsedImplicitly] - get - { - yield return new TestCaseData(typeof(int), false, null); - yield return new TestCaseData(typeof(int), false, new object[] { }); - yield return new TestCaseData(typeof(TestStruct), false, null); - yield return new TestCaseData(typeof(TestStruct), false, new object[] { }); - yield return new TestCaseData(typeof(DefaultConstructor), false, null); - yield return new TestCaseData(typeof(DefaultConstructor), false, new object[] { }); - yield return new TestCaseData(typeof(MultipleConstructors), false, null); - yield return new TestCaseData(typeof(MultipleConstructors), false, new object[] { }); - yield return new TestCaseData(typeof(MultipleConstructors), false, new object[] { 12, 12.5f }); - yield return new TestCaseData(typeof(TemplateStruct), false, null); - yield return new TestCaseData(typeof(TemplateStruct), false, new object[] { }); - yield return new TestCaseData(typeof(TemplateDefaultConstructor), false, null); - yield return new TestCaseData(typeof(TemplateDefaultConstructor), false, new object[] { }); - yield return new TestCaseData(typeof(DefaultConstructorThrows), false, new object[] { 45, 51.0f }); - yield return new TestCaseData(typeof(ParamsOnlyConstructor), false, null); - yield return new TestCaseData(typeof(ParamsOnlyConstructor), false, new object[] { }); - yield return new TestCaseData(typeof(ParamsOnlyConstructor), false, new object[] { 12, 45.5f }); - yield return new TestCaseData(typeof(IntParamsOnlyConstructor), false, null); - yield return new TestCaseData(typeof(IntParamsOnlyConstructor), false, new object[] { }); - yield return new TestCaseData(typeof(IntParamsOnlyConstructor), false, new object[] { 45, 54 }); - yield return new TestCaseData(typeof(NullableIntParamsOnlyConstructor), false, null); - yield return new TestCaseData(typeof(NullableIntParamsOnlyConstructor), false, new object[] { }); - yield return new TestCaseData(typeof(NullableIntParamsOnlyConstructor), false, new object[] { 12, null, 25 }); - yield return new TestCaseData(typeof(DefaultInheritedDefaultConstructor), false, null); - yield return new TestCaseData(typeof(DefaultInheritedDefaultConstructor), false, new object[] { }); - yield return new TestCaseData(typeof(DefaultInheritedNoDefaultConstructor), false, null); - yield return new TestCaseData(typeof(DefaultInheritedNoDefaultConstructor), false, new object[] { }); - yield return new TestCaseData(typeof(DefaultInheritedFromAbstractClass), false, null); - yield return new TestCaseData(typeof(DefaultInheritedFromAbstractClass), false, new object[] { }); - yield return new TestCaseData(typeof(NoDefaultInheritedDefaultConstructor), false, new object[] { 12 }); - yield return new TestCaseData(typeof(NoDefaultInheritedNoDefaultConstructor), false, new object[] { 42 }); - yield return new TestCaseData(typeof(NoDefaultInheritedFromAbstractClass), false, new object[] { 25 }); - yield return new TestCaseData(typeof(int[]), false, new object[] { 5 }); - yield return new TestCaseData(typeof(List), false, null); - yield return new TestCaseData(typeof(List), false, new object[] { }); - yield return new TestCaseData(typeof(List), false, new object[] { 2 }); - yield return new TestCaseData(typeof(List), false, new object[] { Enumerable.Range(0, 5) }); - yield return new TestCaseData(typeof(Dictionary), false, null); - yield return new TestCaseData(typeof(Dictionary), false, new object[] { }); - yield return new TestCaseData(typeof(Dictionary), false, new object[] { 3 }); - - yield return new TestCaseData(typeof(int), true, new object[] { 12 }); - yield return new TestCaseData(typeof(TestStruct), true, new object[] { 12 }); - yield return new TestCaseData(typeof(DefaultConstructor), true, new object[] { 12 }); - yield return new TestCaseData(typeof(MultipleConstructors), true, new object[] { 12.5f, 12 }); - yield return new TestCaseData(typeof(TemplateStruct), true, new object[] { 25 }); - yield return new TestCaseData(typeof(TemplateDefaultConstructor), true, new object[] { 25 }); - yield return new TestCaseData(typeof(NoDefaultConstructor), true, null); - yield return new TestCaseData(typeof(NoDefaultConstructor), true, new object[] { }); - yield return new TestCaseData(typeof(NotAccessibleDefaultConstructor), true, null); - yield return new TestCaseData(typeof(NotAccessibleDefaultConstructor), true, new object[] { }); - yield return new TestCaseData(typeof(AbstractDefaultConstructor), true, null); - yield return new TestCaseData(typeof(AbstractDefaultConstructor), true, new object[] { }); - yield return new TestCaseData(typeof(StaticClass), true, null); - yield return new TestCaseData(typeof(StaticClass), true, new object[] { }); - yield return new TestCaseData(typeof(TemplateStruct<>), true, null); - yield return new TestCaseData(typeof(TemplateStruct<>), true, new object[] { }); - yield return new TestCaseData(typeof(TemplateDefaultConstructor<>), true, null); - yield return new TestCaseData(typeof(TemplateDefaultConstructor<>), true, new object[] { }); - yield return new TestCaseData(typeof(DefaultInheritedDefaultConstructor), true, new object[] { 45 }); - yield return new TestCaseData(typeof(DefaultInheritedNoDefaultConstructor), true, new object[] { 51 }); - yield return new TestCaseData(typeof(DefaultInheritedFromAbstractClass), true, new object[] { 72 }); - yield return new TestCaseData(typeof(NoDefaultInheritedDefaultConstructor), true, new object[] { 45, 35 }); - yield return new TestCaseData(typeof(NoDefaultInheritedNoDefaultConstructor), true, new object[] { 51, 25 }); - yield return new TestCaseData(typeof(NoDefaultInheritedFromAbstractClass), true, new object[] { 72, 15 }); - // ReSharper disable PossibleMistakenCallToGetType.2 - yield return new TestCaseData(typeof(DefaultConstructor).GetType(), true, null); - yield return new TestCaseData(typeof(DefaultConstructor).GetType(), true, new object[] { }); - // ReSharper restore PossibleMistakenCallToGetType.2 - yield return new TestCaseData(typeof(DefaultConstructorThrows), true, null); - yield return new TestCaseData(typeof(DefaultConstructorThrows), true, new object[] { }); - yield return new TestCaseData(typeof(DefaultConstructorThrows), true, new object[] { 12 }); - yield return new TestCaseData(typeof(int[]), true, null); - yield return new TestCaseData(typeof(int[]), true, new object[] { }); - } - } - - [TestCaseSource(nameof(CreateNotDefaultConstructorNoThrowTestCases))] - public void TryNewWithParameters([NotNull] Type type, bool expectFail, [CanBeNull, ItemCanBeNull] params object[] args) + [TestCaseSource(typeof(ConstructorTestHelpers), nameof(CreateNotDefaultConstructorNoThrowTestCases))] + public void TryNewWithParameters([NotNull] Type type, bool expectFail, [CanBeNull, ItemCanBeNull] params object[] arguments) { - var immediateType = new ImmediateType(type); - - Assert.AreEqual(!expectFail, immediateType.TryNew(out object instance, out Exception ex, args)); - if (expectFail) - { - Assert.IsNull(instance); - Assert.IsNotNull(ex); - } - else - { - Assert.IsNotNull(instance); - Assert.AreEqual(Activator.CreateInstance(type, args), instance); - } + ConstructorTestHelpers.TryNewWithParameters( + type, + expectFail, + (out object instance, out Exception exception, object[] args) => + { + var immediateType = new ImmediateType(type); + return immediateType.TryNew(out instance, out exception, args); + }, + arguments); } #endregion diff --git a/src/ImmediateReflection/Extensions/TypeExtensions.cs b/src/ImmediateReflection/Extensions/TypeExtensions.cs index 219271a..4a871f2 100644 --- a/src/ImmediateReflection/Extensions/TypeExtensions.cs +++ b/src/ImmediateReflection/Extensions/TypeExtensions.cs @@ -1,6 +1,9 @@ #if SUPPORTS_CACHING using System; using System.Reflection; +#if SUPPORTS_AGGRESSIVE_INLINING +using System.Runtime.CompilerServices; +#endif using JetBrains.Annotations; namespace ImmediateReflection @@ -72,6 +75,87 @@ public static bool TryNew( return false; } } + + /// + /// Creates an instance of this using the constructor that best matches the specified parameters. + /// + /// It finally uses . + /// to instantiate. + /// + /// An array of arguments that match in number, order, and type the parameters of the constructor to invoke. + /// If is an empty array or null, the constructor that takes no parameters (the default constructor) is invoked. + /// + /// A reference to the newly created object. + /// a RuntimeType or is an open generic type (that is, the ContainsGenericParameters property returns true). + /// Cannot create an instance of an abstract class, or this member was invoked with a late-binding mechanism. + /// No matching public constructor was found. + /// + /// If the cannot be a TypeBuilder. + /// -or- Creation of , ArgIterator, , and types, or arrays of those types, is not supported. + /// -or- The assembly that contains type is a dynamic assembly that was created with Save. + /// -or- The constructor that best matches args has varargs arguments. + /// + /// The constructor being called throws an exception. + /// If the is not a valid type. + [PublicAPI] + [Pure] + [NotNull] + [ContractAnnotation("type:null => halt;args:null => halt")] +#if SUPPORTS_AGGRESSIVE_INLINING + [MethodImpl(MethodImplOptions.AggressiveInlining)] +#endif + public static object New( +#if SUPPORTS_EXTENSIONS + [NotNull] this Type type, +#else + [NotNull] Type type, +#endif + [NotNull, ItemCanBeNull] params object[] args) + { + if (type is null) + throw new ArgumentNullException(nameof(type)); + if (args is null) + throw new ArgumentNullException(nameof(args)); + return TypeAccessor.Get(type).New(args); + } + + /// + /// Tries to create an instance of this with the best matching constructor. + /// + /// + /// This method will not throw if instantiation failed. + /// It finally uses . + /// + /// to instantiate. + /// A reference to the newly created object, otherwise null. + /// Caught exception if the instantiation failed, otherwise null. + /// + /// An array of arguments that match in number, order, and type the parameters of the constructor to invoke. + /// If is an empty array or null, the constructor that takes no parameters (the default constructor) is invoked. + /// + /// True if the new instance was successfully created, false otherwise. + [PublicAPI] + [Pure] + [ContractAnnotation("type:null => halt;args:null => halt;=> true, newInstance:notnull, exception:null;=> false, newInstance:null, exception:notnull")] +#if SUPPORTS_AGGRESSIVE_INLINING + [MethodImpl(MethodImplOptions.AggressiveInlining)] +#endif + public static bool TryNew( +#if SUPPORTS_EXTENSIONS + [NotNull] this Type type, +#else + [NotNull] Type type, +#endif + out object newInstance, + out Exception exception, + [NotNull, ItemCanBeNull] params object[] args) + { + if (type is null) + throw new ArgumentNullException(nameof(type)); + if (args is null) + throw new ArgumentNullException(nameof(args)); + return TypeAccessor.Get(type).TryNew(out newInstance, out exception, args); + } } } #endif \ No newline at end of file