简体   繁体   中英

Finding all classes containing a method in C#

I want to search through all classes in a namespace for those containing a certain method. If a class contains a method then I want to create an instance of the class and run the method.

Obviously I have to start with reflection but I'm stuck on where to go.

Edit:

Interfaces are not the way I want to do this.

What I'm looking for is embedding testing functions into the code but a single calling interface. If there's a self-test function, call it. If there isn't, ignore it.

Create an interface that declares the method and then have various classes implement that interface.

You can then use reflection to find all types within an assembly that implement that interface .

From there you'll need to create an instance of each type and then call the method. The implementation details will vary depending on what you are trying to do.

Update based on comments:

I still think an interface (or attribute) is the way to go. This is how it would work with an interface.

interface ISelfTester
{
    void SelfTest();
}

class SomeClass : ISelfTester
{
    /* ... */

    public void SelfTest() 
    {
        // test code
    }

    /* ... */
}

You could then invoke each type's SelfTest method like so (borrowing from Dathan and Darren Kopp):

var type = typeof(ISelfTester);
var types = AppDomain.CurrentDomain.GetAssemblies()
    .Select(x => x.GetTypes())
    .SelectMany(x => x)
    .Where(x => x.Namespace == "My.Name.Space" && type.IsAssignableFrom(x));

foreach (Type t in types)
{
    ISelfTester obj = Activator.CreateInstance(t) as ISelfTester;
    obj.SelfTest();
}

Without more information about what distinguishes the method, I'm just going to assume it's distinguished by name, and it's public. The name assumption is dangerous, so I wouldn't recommend doing this, but the following should do what you want (assuming Activator is able to create an instance).

EDIT : Added Where(x => x.Namespace == "My.Name.Space") to limit the results to a single target namespace.

EDIT : Added if ... else to handle the case of static methods.

var methods = AppDomain.CurrentDomain.GetAssemblies()
    .Select(x => x.GetTypes())
    .SelectMany(x => x)
    .Where(x => x.Namespace == "My.Name.Space")
    .Where(c => c.GetMethod("MethodName") != null)
    .Select(c => c.GetMethod("MethodName"));

foreach (MethodInfo mi in methods)
{
    if (mi.IsStatic)
    {
        mi.Invoke(null, null); // replace null with the appropriate arguments
    }
    else if (!mi.DeclaringType.IsAbstract)
    {
        var obj = Activator.CreateInstance(mi.DeclaringType);
        mi.Invoke(obj, null); // replace null with the appropriate arguments
    }
}

If you have control over the types, though, jrummel's suggestion about interfaces is a much safer way to do this.

One option would be to use Reflection, as described above, but rather than finding the method by name, look for a method tagged with an appropriate custom attribute. This is similar to what the MS DataContractSerializer does with attributes like [OnDeserializing] . This way the class implementer is specifically spelling out their intent for the method, rather than having it suddenly do something unexpected as a result of it having a particular name.

On a side note, since what you're after is a test method, you might check out something like NUnit . There are several excellent free unit testing frameworks out there. They also provide additional features that can help with your testing, as they provide the scaffolding for the different types of test assertions you might want to make.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM