Вызов статического метода с отражением
У меня есть несколько статических классов в пространстве имен mySolution.Macros
, например
static class Indent{
public static void Run(){
// implementation
}
// other helper methods
}
Итак, мой вопрос в том, как можно будет вызвать эти методы с помощью отражения?
Если методы, в которых НЕ статично, я мог бы сделать что-то вроде:
var macroClasses = Assembly.GetExecutingAssembly().GetTypes().Where( x => x.Namespace.ToUpper().Contains("MACRO") );
foreach (var tempClass in macroClasses)
{
var curInsance = Activator.CreateInstance(tempClass);
// I know have an instance of a macro and will be able to run it
// using reflection I will be able to run the method as:
curInsance.GetType().GetMethod("Run").Invoke(curInsance, null);
}
Я хочу, чтобы мои классы были статичными. Как я смогу сделать что-то подобное со статическими методами?
Короче Я хотел бы вызвать все методы Run из всех статических классов, находящихся в пространстве имен mySolution.Macros.
Ответы
Ответ 1
Как сообщает документация для MethodInfo.Invoke, первый аргумент игнорируется для статических методов, поэтому вы можете просто передать null.
foreach (var tempClass in macroClasses)
{
// using reflection I will be able to run the method as:
tempClass.GetMethod("Run").Invoke(null, null);
}
Как отмечается в комментарии, вы можете убедиться, что метод статичен при вызове GetMethod
:
tempClass.GetMethod("Run", BindingFlags.Public | BindingFlags.Static).Invoke(null, null);
Ответ 2
Вы могли бы действительно, действительно, действительно оптимизировать свой код, заплатив цену за создание делегата только один раз (также нет необходимости создавать экземпляр класса для вызова статического метода). Я сделал что-то очень похожее, и я просто кэшировал делегат метода "Выполнить" с помощью вспомогательного класса :-). Это выглядит так:
static class Indent{
public static void Run(){
// implementation
}
// other helper methods
}
static class MacroRunner {
static MacroRunner() {
BuildMacroRunnerList();
}
static void BuildMacroRunnerList() {
macroRunners = System.Reflection.Assembly.GetExecutingAssembly()
.GetTypes()
.Where(x => x.Namespace.ToUpper().Contains("MACRO"))
.Select(t => (Action)Delegate.CreateDelegate(
typeof(Action),
null,
t.GetMethod("Run", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public)))
.ToList();
}
static List<Action> macroRunners;
public static void Run() {
foreach(var run in macroRunners)
run();
}
}
Это намного быстрее, таким образом.
Если ваша сигнатура метода отличается от Action, вы можете заменить приведение типов и typeof из Action на любой из необходимых универсальных типов Action и Func или объявить свой Delegate и использовать его. Моя собственная реализация использует Func для красивой печати объектов:
static class PrettyPrinter {
static PrettyPrinter() {
BuildPrettyPrinterList();
}
static void BuildPrettyPrinterList() {
printers = System.Reflection.Assembly.GetExecutingAssembly()
.GetTypes()
.Where(x => x.Name.EndsWith("PrettyPrinter"))
.Select(t => (Func<object, string>)Delegate.CreateDelegate(
typeof(Func<object, string>),
null,
t.GetMethod("Print", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public)))
.ToList();
}
static List<Func<object, string>> printers;
public static void Print(object obj) {
foreach(var printer in printers)
print(obj);
}
}
Ответ 3
Я предпочитаю простоту...
private void _InvokeNamespaceClassesStaticMethod(string namespaceName, string methodName, params object[] parameters) {
foreach(var _a in AppDomain.CurrentDomain.GetAssemblies()) {
foreach(var _t in _a.GetTypes()) {
try {
if((_t.Namespace == namespaceName) && _t.IsClass) _t.GetMethod(methodName, (BindingFlags.Static | BindingFlags.Public))?.Invoke(null, parameters);
} catch { }
}
}
}
Использование...
_InvokeNamespaceClassesStaticMethod("mySolution.Macros", "Run");
Но если вы ищете что-то более надежное, включая обработку исключений...
private InvokeNamespaceClassStaticMethodResult[] _InvokeNamespaceClassStaticMethod(string namespaceName, string methodName, bool throwExceptions, params object[] parameters) {
var results = new List<InvokeNamespaceClassStaticMethodResult>();
foreach(var _a in AppDomain.CurrentDomain.GetAssemblies()) {
foreach(var _t in _a.GetTypes()) {
if((_t.Namespace == namespaceName) && _t.IsClass) {
var method_t = _t.GetMethod(methodName, parameters.Select(_ => _.GetType()).ToArray());
if((method_t != null) && method_t.IsPublic && method_t.IsStatic) {
var details_t = new InvokeNamespaceClassStaticMethodResult();
details_t.Namespace = _t.Namespace;
details_t.Class = _t.Name;
details_t.Method = method_t.Name;
try {
if(method_t.ReturnType == typeof(void)) {
method_t.Invoke(null, parameters);
details_t.Void = true;
} else {
details_t.Return = method_t.Invoke(null, parameters);
}
} catch(Exception ex) {
if(throwExceptions) {
throw;
} else {
details_t.Exception = ex;
}
}
results.Add(details_t);
}
}
}
}
return results.ToArray();
}
private class InvokeNamespaceClassStaticMethodResult {
public string Namespace;
public string Class;
public string Method;
public object Return;
public bool Void;
public Exception Exception;
}
Использование в значительной степени то же самое...
_InvokeNamespaceClassesStaticMethod("mySolution.Macros", "Run", false);