Search code examples
c#instancesystem.reflectionnon-staticinvokemember

C# Invoke a non-static method of an instance by string


I have been struggling with a the concept mentioned in the title. I've done a good deal of research and have found some good examples and I have attempted to implement some of them but have reached a road block.

I initially had a class that looked like this:

namespace sysVer
{
    public class testSuite
    {
        /* there is a bunch of test hardware setup
         * and acquisition also that is not shown
         */
        public struct testResultInfo
        {
            public testStatus testStat;
            public bool warning, error;
            public string warnStr, errStr, infoStr, muxDataStr;
            public double measDecVal;
            public Int16 measIntVal;
        };
        
        // NOTE there is no default constructor
        
        public static testResultInfo testCase1()
        {
            
        }
        public static testResultInfo testCase2()
        {
            
        }
        public static testResultInfo testCase3()
        {
            
        }
        // there are about 100 more
    }
}

And using a windows form with 105 of checkboxes and a dictionary to determine which function the user wants to run, I was able to call the functions by a string using Invoke Member as follows:

// first attempt
namespace sysVer
{
    public partial class SysVerForm : Form
    {
        public static Pdgu1553ver.testResultInfo tcResult = new Pdgu1553ver.testResultInfo ( )
        {
            testStat = Pdgu1553ver.testStatus.pass,
            warning = true,
            error = true,
            warnStr = "This is a warning",
            errStr = "This is an error",
            infoStr = "This is info",
            muxDataStr = "Mux data of some sort",
            measDecVal = 69.69,
            measIntVal = 69
        };
        
        // for loop that iterates over checkbox checked items
        foreach ( var checkedItem in checkedItems )
        {
            var funcName = "";
            
            // retrieve function name from dictionary
            tcToFuncDic.TryGetValue ( checkedItem.ToString ( ), out funcName );
            
            tcResult = ( testSuite.testResultInfo ) typeof ( testSuite ).InvokeMember 
                (
                    funcName,
                    BindingFlags.InvokeMethod |
                    BindingFlags.Public |
                    BindingFlags.Static,
                    null,
                    null,
                    null 
                );
        }
    }
}

But I ran into a problem here. When InvokeMember is called the static method is executed and a return type is received but I am not sure if the method is just called or is an actual instance of the class created using the default constructor? I started noticing that private attributes of this class set during one call were not there during another call to a different static function that needed them.

I assumed that I needed an instance of my class so I changed to the following:

namespace sysVer
{
    public class testSuite
    {
        /* there is a bunch of test hardware setup
         * and acquisition also that is not shown
         */
        public struct testResultInfo
        {
            public testStatus testStat;
            public bool warning, error;
            public string warnStr, errStr, infoStr, muxDataStr;
            public double measDecVal;
            public Int16 measIntVal;
        };
        
        // constructor
        public testSuite()
        {
            /* Here I initialize hardware, set variables, and
             * run a few other tasks.  All of which need to be done
             * an exist before this object can be used
             */
        }
        
        public testResultInfo testCase1()
        {
            
        }
        public testResultInfo testCase2()
        {
            
        }
        public testResultInfo testCase3()
        {
            
        }
        //... there are about 100 more
    }
}

Now, I hit another wall. I needed to do something like this:

testSuite myTest = new testSuite();
var blah = myTest.InvokeMember(
                    funcName,
                    BindingFlags.InvokeMethod |
                    BindingFlags.Public |
                    BindingFlags.Static,
                    null,
                    null,
                    null 
                );

But my class does not contain that method. Looking into that I learned that I could change my class to inherit from 'Type' and that I would have to override about 50 or so abstracts from 'Type'. I started down this path but feel that it is likely more work than I need to do here.

I need to have an instance of my class and need to be able to deduce at runtime which non-static method to call. Of the many posts I've read these two: How to invoke a non static method by reflection and invoke non static method in c# seem to be pushing me in the right direction but I'm still missing something somewhere.

I've already put lots of time in overriding all those functions but am stuck there with how to actually implement the overridden InvokeMember function, I'd hate to undo all that work to try to do something else at this point.

As always, any advice is greatly appreciate. Thank you for your time and consideration.


Solution

  • I get the sense you're convoluting a lot of assumptions and concerns with static, structs, reflection, etc. and losing track of where you want to go. You've apparently tried to solve the wrong problems the wrong way. But I'll address your questions one at a time.

    I am not sure if the method is just called or is an actual instance of the class created using the default constructor?

    Why would you think that? You didn't post the code of the test methods but I can assure you that InvokeMember actually invokes the member.

    I started noticing that private attributes of this class set during one call were not there during another call to a different static function that needed them.

    Probably because the test methods create a new testResultInfo each time, but without the code it's impossible to know. But I don't see why that is a problem. What data do you need to "carry over"? Maybe you need a static testResultInfo property on testSuite that you can reuse within the methods?

    Looking into that I learned that I could change my class to inherit from 'Type'

    I can't see any reason whatsoever why you'd need to do that or what you think that would solve.

    Stop trying top band-aid problems that were created by trying to fix other problems, possibly in the wrong way. Back up, analyze your program and think about where different instances are created? should these test methods magically know about the instance that you've created in the form or should they be given that instance somehow? How should you do that? Should you make it an input parameter? Or a static property of the test suite?