RoshanZ
RoshanZ

Reputation: 31

Reflection: Initialize Object Issue

I added reference of one DLL in my project and was successfully able to access methods/classes of that DLL.

Code in DLL: (I do not have access to modify this code)

//Dll: myDllName
    Namespace myNamespace
        Public Class MyClass
                Private Sub New(ByVal parameter1 As Int64)
                    //Set some values
                End Sub

                Public Shared Function MyPublicFunction(ByVal Parameter1 As Int64,ByVal Parameter2 As INt64,ByVal Parameter2 As Int64) As MyClass
                Dim retMyClass As New MyClass(Parameter1)
                //Set Other Values

                Return retMyClass
          End Function

          Public Function Post() As Boolean
            //Do some operation
          End Function
        End Class
    End Namespace

My code where I have called above DLL:

Dim myObj As myDllName.myNamespace.MyClass
myObj = myDllName.myNamespace.MyClass.MyPublicFunction(Parameter1, Parameter2, Parameter3)

myObj.Prop1 = MyVal1
myObj.Prop2 = MyVal2
myObj.Prop3 = MyVal1
myObj.Post()

Now my requirement is I want to achieve above task without adding reference of DLL to the project. So I tried to achieve this with reflection.

Dim assembly As Reflection.Assembly = Reflection.Assembly.LoadFile("..\\myDllName.dll")
Dim t As Type = assembly.GetType("myDllName.myNamespace.MyClass")
Dim woFacadeinst As Object = Activator.CreateInstance(t)

But on object initialization it throws me error that Constructor on type

myDllName.myNamespace.MyClass

not found.

I think it is because of the Private NEW method in my DLL reference class. Can someone help with this?

Upvotes: 0

Views: 659

Answers (3)

Martin Backasch
Martin Backasch

Reputation: 1899

You are running into this exception, because with this line

Dim woFacadeinst As Object = Activator.CreateInstance(t)

you try to call a parameter less constructor, which does not exist.

So you have to call Activator.CreateInstance() with some more parameters to pass the required parameter to the constructor.

Private Sub New(ByVal parameter1 As Int64)
    'Set some values
End Sub

Usually in C# I used the following snippet:

var woFacadeinst = Activator.CreateInstance( typeof(Class1), BindingFlags.NonPublic | BindingFlags.Instance,  
                                             null, new object[] { 5 }, null );

and as vb.Net:

Dim woFacadeinst As Object = Activator.CreateInstance( GetType(Class1),  
                                                       BindingFlags.NonPublic Or BindingFlags.Instance,
                                                       Nothing, New Object(){ 5 }, Nothing)

The trick to get the private constructor are the right Bindingflags and with new object[]{ 5 } you are setting the parameter(s) requied by the constructor.


Hint: For performance concerns take a look at the Ali Ezzat Odeh' Answer.

If you want to use the GetConstructor() method you can do this like the following C# snippet:

 var test = typeof(Class1).GetConstructor( BindingFlags.NonPublic | BindingFlags.Instance,
                                            null, new Type[] { typeof(Int64) }, null )
                          ?.Invoke( new object[] { 64 } );

As C# Example:

The Class:

public class Class1
{
    private Class1(string myString)
    {
        MyIntProperty = 42;
        MyStringProperty = myString;
    }

    private Class1(int myInt)
    {
        MyIntProperty = myInt;
        MyStringProperty = "default";
    }

    private Class1(Int64 myInt64)
    {
        MyInt64Property = myInt64;
        MyStringProperty = "default";
    }

    public string MyStringProperty { get; set; }
    public int MyIntProperty { get; set; }
    public Int64 MyInt64Property { get; set; }
}

and the test snippet:

string testString = "Test";
int testInt = 123;

var objArray = new object[1];

objArray[0] = testString;
var testClass1 = Activator.CreateInstance( typeof(Class1), BindingFlags.NonPublic | BindingFlags.Instance,
                                           null, objArray, null );

objArray[0] = testInt;
var testClass2 = Activator.CreateInstance( typeof(Class1), BindingFlags.NonPublic | BindingFlags.Instance, 
                                           null, objArray, null );

var testCtorClass = typeof(Class1).GetConstructor( BindingFlags.NonPublic | BindingFlags.Instance,
                                                   null, new Type[] { typeof(Int64) }, null )
                                  ?.Invoke( new object[] { 64 } );

Upvotes: 0

Dogu Arslan
Dogu Arslan

Reputation: 3384

you could try var myClass = FormatterServices.GetUninitializedObject(typeof(MyClass)); This api does not use any constructor so it does not have any constructor requirements.

Upvotes: 0

Ali Ezzat Odeh
Ali Ezzat Odeh

Reputation: 2163

For parameterized constructor use GetConstructors() and Invoke() instead of Activator.CreateInstance() as the following :

 Dim constructor = t.GetConstructors(BindingFlags.NonPublic Or BindingFlags.Instance)

 Dim woFacadeinst As Object = constructor(0).Invoke(New Object() {5})

because it takes more time, check the graph in this link and if the performance really matters for you try compiled lambda expressions, it is way faster than both.

Upvotes: 1

Related Questions