리플렉션을 사용하여 정적 메서드 호출
네임 스페이스에 다음 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);
}
내 수업을 정적으로 유지하고 싶습니다. 정적 메서드로 비슷한 작업을 어떻게 수행 할 수 있습니까?
간단히 말해서 mySolution.Macros 네임 스페이스에있는 모든 정적 클래스에서 모든 Run 메서드를 호출하고 싶습니다.
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);
대리자를 한 번만 생성하는 비용을 지불하면 실제로 코드를 많이 최적화 할 수 있습니다 (정적 메서드를 호출하기 위해 클래스를 인스턴스화 할 필요도 없음). 나는 매우 비슷한 일을했고, 헬퍼 클래스의 도움으로 "Run"메소드에 델리게이트를 캐시했습니다. :-). 다음과 같이 보입니다.
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과 다른 경우 Action의 type-cast 및 typeof를 필요한 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);
}
}
나는 단순함을 선호한다 ...
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);
참고URL : https://stackoverflow.com/questions/11908156/call-static-method-with-reflection
'developer tip' 카테고리의 다른 글
std :: lock_guard 또는 std :: scoped_lock? (0) | 2020.08.22 |
---|---|
IISExpress 로그 파일 위치 (0) | 2020.08.22 |
C #에 JWT (JSON Web Token) 예제가 있습니까? (0) | 2020.08.22 |
Visual Studio 2013 git, 마스터 분기 만 나열 됨 (0) | 2020.08.22 |
Python에서 Google Authenticator 구현 (0) | 2020.08.22 |