Есть ли C # эквивалент Perl AUTOLOAD? - PullRequest
0 голосов
/ 06 сентября 2011

Есть ли способ динамически перехватывать вызовы методов в классе в C #, эквивалентном механизму Perl AUTOLOAD?

В данном случае у меня есть вспомогательный класс с методом «core», который записывает в системный журнал событий, и несколько вспомогательных перегрузок для упрощения наиболее распространенного использования.

Теперь я вижу появляющийся шаблон кода, в котором я использую 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 голосов
/ 06 сентября 2011

О ... К моему большому удивлению, я понял это за чашкой кофе, и это действительно работает. Перефразируя исходный фрагмент кода, вот что я сделал:

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)

Небольшое предупреждение: приведенный выше код очищен для размещения на официальном форуме, он может не работать "из коробки".

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