Running into System.MissingMethodException: Method

2020-08-25 05:06发布

问题:

Basically, some of my tests are succeeding, some are failing. Per Mr. Skeet's excellent suggestion, I created a full code sample to confirm I'm not crazy. This is the code:

namespace ClassLibrary
{
    using System;

    public class Manager
    {
        private int SampleMethod(int id)
        {
            return id;
        }
    }
}

My test is:

namespace UnitTestProject
{
    using System;
    using Microsoft.VisualStudio.TestTools.UnitTesting;

    [TestClass]
    public class UnitTest
    {
        [TestMethod]
        public void TestPasses()
        {
            var privateInfo = new PrivateObject(new ClassLibrary.Manager());
            var actual = privateInfo.Invoke("SampleMethod", 1);
        }

        [TestMethod]
        public void TestErrorsOut()
        {
            var privateInfo = new PrivateObject(new ClassLibrary.Manager());
            var actual = privateInfo.Invoke("SampleMethod", 0);
        }

        [TestMethod]
        public void TestWorksAsWell()
        {
            var privateInfo = new PrivateObject(new ClassLibrary.Manager());
            privateInfo.Invoke("SampleMethod", new object[] { 0 });
        }

        [TestMethod]
        public void TestAlsoErrorsOut()
        {
            var privateInfo = new PrivateObject(new ClassLibrary.Manager());
            var types = new Type[] { typeof(int) };
            var actual = privateInfo.Invoke("SampleMethod", types, 0);
        }
    }
}

The first test (TestPasses()) works.

The second test (TestErrorsOut()) fails with the following error: {"Method 'ClassLibrary.Manager.SampleMethod' not found."}

The baffling thing is the error is consistent, but the actual test is almost identical. It makes no sense. I tried this on VS2012 RC and VS2010, with the same results.

The only thing I can think of is "0" is getting cast as something besides int, which means it can't find the method signature of SampleMethod? I tried a third test to explicitly pass in the type I'm looking for (TestAlsoErrorsOut()), but that also errors out with the same error.

Ideas? Thanks.

Edit to add

By using Ian's suggestion of using the obj[] instead of params obj[] overload, it works (test TestWorksAsWell()). And that explains why TestAlsoErrorsOut() fails, because I'm using params method, which wouldn't work with Type[]. So, this is fixed. But, why? Why will params obj[] work when passing a 1, but not a 0?

回答1:

According to the docs (http://msdn.microsoft.com/en-us/library/ms243710.aspx) the arguments are supposed to be passed as an array of objects. Explicitly passing an object array appears to work correctly:

var actual = (int)privateInfo.Invoke("SampleMethod", new object[] {0});

Passing 0 on its own appears to result in the compiler selecting this overload

Invoke(string name = "SampleMethod", System.Reflection.BindingFlags bindingFlags = Default, object[] args = {object[0]})


回答2:

I was getting the System.MissingMethodException when calling the following test:

PrivateObject shadow = new PrivateObject(target);    
shadow.Invoke("PrivateMethod", new string[]{"arg1","arg2"});

On the target's private method signature

private void PrivateMethod(string[] args)

I had to add params to the private method signature to resolve the exception as follows:

private void PrivateMethod(params string[] args)


回答3:

Ian Gilroy is right, but the reason why; it is because PrivateObject.Invoke has many signatures, and one of them is: Invoke(string name, Type[] types, object[] objects).

And in my case, I was passing values like: Invoke("MethodName", null, null), in which case C# compiler prefers the mentioned signature, than Invoke(string name, params object[] objects), which results in error.