Поиск всех классов, содержащих метод в C # - PullRequest
5 голосов
/ 05 мая 2010

Я хочу найти во всех классах пространства имен те, которые содержат определенный метод. Если класс содержит метод, я хочу создать экземпляр класса и запустить метод.

Очевидно, я должен начать с размышления, но я застрял в том, куда идти.

Edit:

Интерфейсы - не тот способ, которым я хочу это делать.

Я ищу встраивание функций тестирования в код, но единый вызывающий интерфейс. Если есть функция самопроверки, вызовите ее. Если нет, игнорируйте это.

Ответы [ 3 ]

11 голосов
/ 05 мая 2010

Без дополнительной информации о том, что отличает метод, я просто собираюсь предположить, что он различается по имени, и он общедоступен. Предположение имени опасно, поэтому я бы не рекомендовал делать это, но следующее должно делать то, что вы хотите (при условии, что Activator может создать экземпляр).

РЕДАКТИРОВАТЬ : Добавлено Where(x => x.Namespace == "My.Name.Space"), чтобы ограничить результаты одним целевым пространством имен.

EDIT : добавлено if ... else для обработки случая статических методов.

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
    }
}

Если у вас есть контроль над типами, предложение jrummel об интерфейсах - гораздо более безопасный способ сделать это.

11 голосов
/ 05 мая 2010

Создайте интерфейс, который объявляет метод и затем различные классы реализуют этот интерфейс.

Затем можно использовать отражение, чтобы найти все типы в сборке, реализующей этот интерфейс .

Оттуда вам нужно создать экземпляр каждого типа, а затем вызвать метод. Детали реализации будут зависеть от того, что вы пытаетесь сделать.

Обновление на основе комментариев:

Я все еще думаю, что интерфейс (или атрибут) - это путь. Вот как это будет работать с интерфейсом.

interface ISelfTester
{
    void SelfTest();
}

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

    public void SelfTest() 
    {
        // test code
    }

    /* ... */
}

Затем вы можете вызывать метод SelfTest каждого типа следующим образом (позаимствовано у Дафана и Даррена Коппа):

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();
}
2 голосов
/ 06 мая 2010

Одним из вариантов будет использование Reflection, как описано выше, но вместо того, чтобы находить метод по имени, ищите метод, помеченный соответствующим пользовательским атрибутом. Это похоже на то, что MS DataContractSerializer делает с такими атрибутами, как [OnDeserializing]. Таким образом, разработчик класса специально указывает свое намерение для метода, а не заставляет его внезапно сделать что-то неожиданное из-за того, что у него есть определенное имя.

На заметку: поскольку вы ищете тестовый метод, вы можете проверить что-то вроде NUnit . Есть несколько отличных бесплатных платформ для модульного тестирования. Они также предоставляют дополнительные функции, которые могут помочь в вашем тестировании, поскольку они предоставляют леса для различных типов тестовых утверждений, которые вы, возможно, захотите сделать.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...