有没有办法在C#中动态拦截类中的方法调用,相当于Perl AUTOLOAD机制?
例如,我有一个带有'核心'方法的辅助类,它写入系统事件日志和一些便利重载,以简化最常见的用途。
现在,我看到一种新兴的代码模式,我使用try ... catch来尝试编写一个条目,但忽略了与实际事件日志处理相关的任何故障。例如,当事件日志已满时尝试记录应用程序异常时,我希望应用程序崩溃“真正的”应用程序异常,而不是“事件日志”异常。
我目前刚刚创建了一组新的重载,它封装了这个,但我真正想做的是对这些方法进行动态处理,即对以“Try”开头的方法名称的任何方法调用都会调用相应的“真正的“方法,封装在一个try .. catch。这在Perl中很容易;-)但是它甚至可以在C#中完成吗?
一些可能简化解释的代码:
public class SomeClass
{
// Core functionality
public static void WriteToLog(string message, EventLogEntryType type)
{
...
}
// Overloaded methods for common uses
public static void WriteToLog(SomeObject obj)
{
WriteToLog(obj.ToString(), EventLogEntryType.Information);
}
public static void WriteToLog(SomeException ex)
{
WriteToLog(ex.Message, EventLogEntryType.Error);
}
// Additional wrappers that ignores errors
// These are what I'd like to handle dynamically instead of manually:
public static void TryWriteToLog(SomeObject obj)
{
try
{
WriteToLog(obj);
}
catch (Exception logException)
{
Console.WriteLine(logException.Message);
}
}
public static void TryWriteToLog(SomeException ex)
{
try
{
WriteToLog(ex);
}
catch (Exception logException)
{
Console.WriteLine(logException.Message);
}
}
}
答案 0 :(得分:0)
...喔 令我惊讶的是,我想出了一杯咖啡,它确实有效。为了解释最初的代码片段,这就是我所做的:
using System;
using System.Dynamic;
using System.Reflection;
public class SomeClass : DynamicObject
{
// Core functionality
public static void WriteToLog(string message, EventLogEntryType type)
{
...
}
// Overloaded methods for common uses
public static void WriteToLog(SomeObject obj)
{
WriteToLog(obj.ToString(), EventLogEntryType.Information);
}
public static void WriteToLog(SomeException ex)
{
WriteToLog(ex.Message, EventLogEntryType.Error);
}
// Redirect all method calls that start with 'Try' to corresponding normal
// methods, but encapsulate the method call in a try ... catch to ignore
// log-related errors
private static dynamic instance = new SomeClass();
public static dynamic Instance { get { return instance; } }
public override bool TryInvokeMember(InvokeMemberBinder binder,
object[] args,
out object result)
{
if (binder.Name.StartsWith("Try"))
{
try
{
result = this.GetType().InvokeMember(binder.Name.Substring(3),
BindingFlags.InvokeMethod,
null,
this,
args);
}
catch (Exception ex)
{
Console.WriteLine(ex.InnerException.Message);
result = null;
}
return true;
}
else
{
return base.TryInvokeMember(binder, args, out result);
}
}
现在可以调用以下方法,并且似乎按预期工作:
SomeClass.Instance.WriteToLog(SomeObject obj)
SomeClass.Instance.TryWriteToLog(SomeObject obj)
SomeClass.Instance.WriteToLog(SomeException ex)
SomeClass.Instance.TryWriteToLog(SomeException ex)
SomeClass.Instance.WriteToLog(string message, EventLogEntryType type)
SomeClass.Instance.TryWriteToLog(string message, EventLogEntryType type)
小警告:上述代码已清理,以便在官方论坛上发布,它可能无法开箱即用。