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?


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.

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";
        }
    }
}

 

Login or Signup to post a comment