Search code examples
c#reflectionsystem.reflection

Call non-static member of static property in static class with reflection


I have a static class which looks for an implementation of an abstract type and stores it as a static property similar to the below:

public static class MyStaticClass
{
    private static MyAbstractType _MyAbstractImplementation;

    public static MyAbstractType MyAbstractImplementation
    {
        get => _MyAbstractImplementation ?? ( _MyAbstractImplementation = FindImplementation());
        private set => _MyAbstractImplementation = value;
    }
}

And I am trying to call a method of MyAbstractImplementation (which contains no static properties or methods) via reflection:

var myAssembly = Assembly.Load("MyStaticClassAssembly")

var myType = myAssembly.GetTypes().First(t => t.Name == "MyAbstractType");

var myImplementation = myType.GetProperties()
    .First(p=>p.ReflectedType?.Name == "MyAbstractImplementation")
    .GetValue(null);

var obj = myType.GetMethod("SomeMethod")?.Invoke(
                null,
                new object[] 
                {
                    // Some args
                });

The above code causes the following exception on getting the value of MyAbstractImplementation:

System.Reflection.TargetException: Non-static method requires a target.

Evidently, this is because I am passing null to GetValue(), so I try passing myAssembly rather than null and I get the following exception:

System.Reflection.TargetException: Object does not match target type.

Out of desperation, I try passing myType and myImplementation but I still get the same exception.

What am I meant to be passing to GetValue()?


Solution

  • From the error you are getting MyAbstractImplementation is not a static property, so it needs an instance to be run on. You are basically trying to write the following code:

    new MyAbstractType().MyAbstractImplementation.SomeMethod();
    

    Both the property and method access need the target to run against (the left side of '.'). So you need an instance of myType. Also the method will need the instance, which is the result of getting the property (myImplementation).

    var myAssembly = Assembly.Load("MyStaticClassAssembly");
    
    var myType = myAssembly.GetTypes().First(t => t.Name == "MyAbstractType");
    var myTypeInstance = Activator.CreateInstance(myType);  // Asuming has a default constructor 
    
    var myImplementation = myType.GetProperties()
        .First(p => p.ReflectedType?.Name == "MyAbstractImplementation")
        .GetValue(myTypeInstance);
    
    var obj = myType.GetMethod("SomeMethod")?.Invoke(
                    myImplementation,
                    new object[]
                    {
                        // Some args
                    });
    

    From how you write the code myImplementation should also be of type myType (myType.GetMethod("SomeMethod")) if it isn't replace it with: myImplementation.GetType().GetMethod("SomeMethod").