CreateInstanceAccessor Class

Provides an efficient way for creating objects via dynamically created delegates.

Definition

Namespace: KGySoft.Reflection
Assembly: KGySoft.CoreLibraries (in KGySoft.CoreLibraries.dll) Version: 9.0.0-preview.1
C#
public abstract class CreateInstanceAccessor : MemberAccessor
Inheritance
Object    MemberAccessor    CreateInstanceAccessor

Remarks

You can obtain a CreateInstanceAccessor instance by the static GetAccessor methods. There are two overloads of them: GetAccessor(Type) can be used for types with parameterless constructors and for creating value types without a constructor, and the GetAccessor(ConstructorInfo) overload is for creating an instance by a specified constructor (with or without parameters).

The CreateInstance(Object) method can be used to create an instance of an object in general cases. It can be used even for constructors with parameters passed by reference. To obtain the result of possible ref/ parameters, pass a preallocated array to the CreateInstance(Object) method. The parameters passed by reference will be assigned back to the corresponding array elements.

The other non-generic CreateInstance overloads can be used for constructors with no more than four parameters. They provide a better performance than the general CreateInstance(Object) method but the result of parameters passed reference will not be assigned back.

If you know the type of the created instance and the parameter types at compile time, then you can use the generic CreateInstance methods for even better performance. These strongly typed methods can be used as long as the constructors to invoke have no more than four parameters. Parameters passed by reference are also supported but only as input parameters as they are not assigned back to the caller.

The first call of these methods is slower because the delegate is generated on the first access, but further calls are much faster.

The already obtained accessors are cached so subsequent GetAccessor calls return the already created accessors unless they were dropped out from the cache, which can store about 8000 elements.

  Note

If you want to create an instance just by enlisting the constructor parameters of a Type rather than specifying a ConstructorInfo, then you can use the CreateInstance methods in the Reflector class, which have some overloads for that purpose.

Example

The following example compares the CreateInstanceAccessor class with System.Reflection alternatives on .NET 8 and .NET Framework 4.8 platforms.
C#
using System;
using System.Reflection;
using System.Runtime.Versioning;

using KGySoft.Diagnostics;
using KGySoft.Reflection;

class Example
{
    private class TestClass
    {
        public TestClass() { }
        public TestClass(int i) { }
    }

    private static string PlatformName => ((TargetFrameworkAttribute)Attribute.GetCustomAttribute(Assembly.GetExecutingAssembly(),
        typeof(TargetFrameworkAttribute))).FrameworkDisplayName;

    static void Main()
    {
        Type testType = typeof(TestClass);
        ConstructorInfo ctor = testType.GetConstructor(Type.EmptyTypes);
        CreateInstanceAccessor accessor = CreateInstanceAccessor.GetAccessor(testType);

        new PerformanceTest<TestClass> { TestName = $"Default Constructor - {PlatformName}", Iterations = 1_000_000 }
            .AddCase(() => new TestClass(), "Direct call")
            .AddCase(() => (TestClass)Activator.CreateInstance(testType), "System.Activator.CreateInstance")
            .AddCase(() => (TestClass)ctor.Invoke(null), "System.Reflection.ConstructorInfo.Invoke")
            .AddCase(() => (TestClass)accessor.CreateInstance(), "CreateInstanceAccessor.CreateInstance")
            .AddCase(() => accessor.CreateInstance<TestClass>(), "CreateInstanceAccessor.CreateInstance<>")
            .DoTest()
            .DumpResults(Console.Out);

        ctor = testType.GetConstructor(new[] { typeof(int) });
        accessor = CreateInstanceAccessor.GetAccessor(ctor);
#if NET8_0_OR_GREATER
        ConstructorInvoker invoker = ConstructorInvoker.Create(ctor);
#endif
        new PerformanceTest<TestClass> { TestName = $"Parameterized Constructor - {PlatformName}", Iterations = 1_000_000 }
            .AddCase(() => new TestClass(1), "Direct call")
            .AddCase(() => (TestClass)Activator.CreateInstance(testType, 1), "System.Activator.CreateInstance")
            .AddCase(() => (TestClass)ctor.Invoke(new object[] { 1 }), "System.Reflection.ConstructorInfo.Invoke")
#if NET8_0_OR_GREATER
            .AddCase(() => (TestClass)invoker.Invoke(1), "System.Reflection.ConstructorInvoker.Invoke (.NET 8 or later)")
#endif
            .AddCase(() => (TestClass)accessor.CreateInstance(1), "CreateInstanceAccessor.CreateInstance")
            .AddCase(() => accessor.CreateInstance<TestClass, int>(1), "CreateInstanceAccessor.CreateInstance<,>")
            .DoTest()
            .DumpResults(Console.Out);
    }
}

// This code example produces a similar output to these ones:

// ==[Default Constructor - .NET 8.0 Results]================================================
// Iterations: 1,000,000
// Warming up: Yes
// Test cases: 5
// Calling GC.Collect: Yes
// Forced CPU Affinity: No
// Cases are sorted by time (quickest first)
// --------------------------------------------------
// 1. Direct call: average time: 8.66 ms
// 2. CreateInstanceAccessor.CreateInstance<>: average time: 9.48 ms (+0.83 ms / 109.53%)
// 3. CreateInstanceAccessor.CreateInstance: average time: 9.90 ms (+1.25 ms / 114.41%)
// 4. System.Activator.CreateInstance: average time: 12.84 ms (+4.18 ms / 148.32%)
// 5. System.Reflection.ConstructorInfo.Invoke: average time: 13.30 ms (+4.65 ms / 153.70%)
//
// ==[Parameterized Constructor - .NET 8.0 Results]================================================
// Iterations: 1,000,000
// Warming up: Yes
// Test cases: 6
// Calling GC.Collect: Yes
// Forced CPU Affinity: No
// Cases are sorted by time (quickest first)
// --------------------------------------------------
// 1. Direct call: average time: 5.83 ms
// 2. CreateInstanceAccessor.CreateInstance<,>: average time: 9.58 ms (+3.74 ms / 164.15%)
// 3. CreateInstanceAccessor.CreateInstance: average time: 15.45 ms (+9.61 ms / 264.79%)
// 4. System.Reflection.ConstructorInvoker.Invoke (.NET 8 or later): average time: 16.64 ms (+10.81 ms / 285.30%)
// 5. System.Reflection.ConstructorInfo.Invoke: average time: 40.69 ms (+34.85 ms / 697.44%)
// 6. System.Activator.CreateInstance: average time: 271.66 ms (+265.83 ms / 4,656.86%)

// ==[Default Constructor - .NET Framework 4.8 Results]================================================
// Iterations: 1,000,000
// Warming up: Yes
// Test cases: 5
// Calling GC.Collect: Yes
// Forced CPU Affinity: No
// Cases are sorted by time (quickest first)
// --------------------------------------------------
// 1. Direct call: average time: 5.57 ms
// 2. CreateInstanceAccessor.CreateInstance<>: average time: 14.13 ms (+8.56 ms / 253.57%)
// 3. CreateInstanceAccessor.CreateInstance: average time: 32.48 ms (+26.91 ms / 582.84%)
// 4. System.Activator.CreateInstance: average time: 48.24 ms (+42.67 ms / 865.77%)
// 5. System.Reflection.ConstructorInfo.Invoke: average time: 204.87 ms (+199.30 ms / 3,676.54%)
//
// ==[Parameterized Constructor - .NET Framework 4.8 Results]================================================
// Iterations: 1,000,000
// Warming up: Yes
// Test cases: 5
// Calling GC.Collect: Yes
// Forced CPU Affinity: No
// Cases are sorted by time (quickest first)
// --------------------------------------------------
// 1. Direct call: average time: 5.43 ms
// 2. CreateInstanceAccessor.CreateInstance<,>: average time: 14.28 ms (+8.85 ms / 263.06%)
// 3. CreateInstanceAccessor.CreateInstance: average time: 18.96 ms (+13.53 ms / 349.15%)
// 4. System.Reflection.ConstructorInfo.Invoke: average time: 199.26 ms (+193.83 ms / 3,669.64%)
// 5. System.Activator.CreateInstance: average time: 682.53 ms (+677.10 ms / 12,569.87%)

Properties

MemberInfo Gets the reflection member info of the accessed member.
(Inherited from MemberAccessor)

Methods

CreateInstance Creates a new instance using the associated Type or parameterless constructor.
See the Remarks section of the CreateInstance(Object) overload for details.
CreateInstance(Object) Creates a new instance using the associated constructor with one parameter.
See the Remarks section of the CreateInstance(Object) overload for details.
CreateInstance(Object) Creates a new instance by the associated ConstructorInfo or Type. For types and parameterless constructors the parameters parameter is omitted.
CreateInstance(Object, Object) Creates a new instance using the associated constructor with two parameters.
See the Remarks section of the CreateInstance(Object) overload for details.
CreateInstance(Object, Object, Object) Creates a new instance using the associated constructor with three parameters.
See the Remarks section of the CreateInstance(Object) overload for details.
CreateInstance(Object, Object, Object, Object) Creates a new instance using the associated constructor with four parameters.
See the Remarks section of the CreateInstance(Object) overload for details.
CreateInstanceTInstance Creates a new instance using the associated Type or parameterless constructor.
CreateInstanceTInstance, T(T) Creates a new instance using the associated constructor with one parameter.
CreateInstanceTInstance, T1, T2(T1, T2) Creates a new instance using the associated constructor with two parameters.
CreateInstanceTInstance, T1, T2, T3(T1, T2, T3) Creates a new instance using the associated constructor with three parameters.
CreateInstanceTInstance, T1, T2, T3, T4(T1, T2, T3, T4) Creates a new instance using the associated constructor with four parameters.
Equals Determines whether the specified Object is equal to the current MemberAccessor.
(Inherited from MemberAccessor)
GetAccessor(ConstructorInfo) Gets a CreateInstanceAccessor for the specified ConstructorInfo.
GetAccessor(Type) Gets a CreateInstanceAccessor for the specified Type. Given type must have a parameterless constructor or must be a ValueType.
GetHashCode Gets a hash code for the current MemberAccessor instance.
(Inherited from MemberAccessor)
ToString Returns a String that represents the current MemberAccessor.
(Inherited from MemberAccessor)

Extension Methods

Convert Converts an Object specified in the obj parameter to the desired targetType.
See the Examples section of the generic ConvertTTarget(Object, CultureInfo) overload for an example.
(Defined by ObjectExtensions)
ConvertTTarget Converts an Object specified in the obj parameter to the desired TTarget.
(Defined by ObjectExtensions)
In Gets whether item is among the elements of set.
See the Examples section of the generic InT(T, T) overload for an example.
(Defined by ObjectExtensions)
TryConvert Tries to convert an Object specified in the obj parameter to the desired targetType.
See the Examples section of the ConvertTTarget(Object, CultureInfo) method for a related example.
(Defined by ObjectExtensions)
TryConvert Tries to convert an Object specified in the obj parameter to the desired targetType.
See the Examples section of the ConvertTTarget(Object, CultureInfo) method for a related example.
(Defined by ObjectExtensions)
TryConvertTTarget Tries to convert an Object specified in the obj parameter to the desired TTarget.
See the Examples section of the ConvertTTarget(Object, CultureInfo) method for a related example.
(Defined by ObjectExtensions)
TryConvertTTarget Tries to convert an Object specified in the obj parameter to the desired TTarget.
See the Examples section of the ConvertTTarget(Object, CultureInfo) method for a related example.
(Defined by ObjectExtensions)

See Also