是否有任何C#等同于Perl AUTOLOAD?

时间:2011-09-06 13:48:40

标签: c# reflection

有没有办法在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);
        }
    }
}

1 个答案:

答案 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)

小警告:上述代码已清理,以便在官方论坛上发布,它可能无法开箱即用。