Start a new topic

FormatterServices.GetUninitializedObject alternative?

I need to create an instance of a type that might be without parameterless constructor...

In .net you'd do 'FormatterServices.GetUninitializedObject(myType)' to achieve that. Can you suggest an alternative?


'Activator.CreateInstance(type)' will fail in that scenario.


class for example:


public class MyClass{

  public MyClass(int a, string b) { }

}


How can DuoCode create an instance of this class at runtime?


Attaching use of Activator from our tests.


using System;
using System.Linq;

namespace DuoCode.Tests.Reflection
{
    [TestFixture]
    public class ConstructorInfoTests
    {
        [Test]
        public void InvokeParameterless()
        {
            var type = typeof(TestClass);
            var constructor = type.GetConstructors().Single(x => x.GetParameters().Length == 0);
            var testClass = (TestClass)constructor.Invoke();
            QUnit.AreEqual(testClass.Foo, "parameterless");
        }

        [Test]
        public void InvokeWithParameters()
        {
            var type = typeof(TestClass);
            var constructor1 = type.GetConstructors().Single(x => x.GetParameters().Length == 1);
            var testClass1 = (TestClass)constructor1.Invoke("a");
            QUnit.AreEqual(testClass1.Foo, "a");

            var constructor2 = type.GetConstructors().Single(x => x.GetParameters().Length == 2);
            var testClass2 = (TestClass)constructor2.Invoke("a", "b");
            QUnit.AreEqual(testClass2.Foo, "ab");

            // wrong number of arguments
            QUnitUtils.Throws<Exception>(() => constructor2.Invoke());
            QUnitUtils.Throws<Exception>(() => constructor2.Invoke("a"));
            QUnitUtils.Throws<Exception>(() => constructor2.Invoke("a", "b", "c"));
        }

        [Test]
        public void CreateUsingActivator()
        {
            var type = typeof(TestClass);
            var testClass1 = (TestClass)Activator.CreateInstance(type);
            QUnit.AreEqual(testClass1.Foo, "parameterless");

            var testClass2 = (TestClass)Activator.CreateInstance(type, "a");
            QUnit.AreEqual(testClass2.Foo, "a");

            var testClass3 = (TestClass)Activator.CreateInstance(type, "a", "b");
            QUnit.AreEqual(testClass3.Foo, "ab");

            // wrong number of arguments
            QUnitUtils.Throws<Exception>(() => Activator.CreateInstance(type, "a", "b", "c"));
        }

        [Test]
        public void InvokeNoConstructor()
        {
            var type = typeof(NoConstructorClass);
            var constructor = type.GetConstructors().Single(x => x.GetParameters().Length == 0);
            var testClass = (NoConstructorClass)constructor.Invoke(null);
            QUnit.AreEqual(testClass.Foo, "noconstructor");
        }

        public class TestClass
        {
            public string Foo;

            public TestClass()
            {
                Foo = "parameterless";
            }

            public TestClass(string s1)
            {
                Foo = s1;
            }

            public TestClass(string s1, string s2)
            {
                Foo = s1 + s2;
            }
        }

        public class NoConstructorClass
        {
            public string Foo = "noconstructor";
        }
    }
}

 

This will achieve that:

var ctors = type.GetConstructors();
 if (ctors == null || ctors.Count == 0)
 {
 var privateCtor = type.GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance, null, new Type[0], null);
 ctors = new ConstructorInfo[] { privateCtor };
 }

 var instance = ctors[0].Invoke(null);


My actual problem was I was trying to initialize an Enum. That solved by checking myType.IsEnum and manually creating it's initial value:

Enum.GetValues(myType)[0];


Though, FormatterServices.GetUninitializedObject does pretty good job covering those and probably more variations. Would be happy to know if that's also possible in DuoCode.

Login or Signup to post a comment