2012-05-22 2 views
5

Скажем, у меня есть интерфейс, как это:Использование методов расширения внутри расширенного класса сам

public interface ILoggable 
{ 
    void Log(Func<string> message, Logger.Type type); 
} 

И некоторые расширения методов, как это:

public static class Logger 
{ 
    public static void Log(this ILoggable loggable, Func<string> message) { loggable.Log(message, Type.Information); } 
    public static void Log(this ILoggable loggable, string prefix, byte[] data, int len) { /* snip */ } 
    public static void Log(this ILoggable loggable, Exception ex) { /* snip */ } 
    // And so on... 
} 

Тогда в любом class CoreService : ServiceBase, ILoggable или такой я реализовать что public void Log(Func<string> message, Logger.Type type) на все, что мне нравится (public modifier is kind meh ...) и использовать все методы расширения для фактического ведения журнала.

Пока все хорошо ... или не так хорошо? Что-то не так с этим подходом? Если нет, то почему неудобством:

catch (Exception ex) { 
    this.Log(ex); // this works 
    Log(ex); // this goes not 
+0

Вы также можете вызвать 'Log (this, ex)', который кажется более читаемым в этой ситуации. –

+0

@HenkHolterman: Ну, вам придется звонить Logger.Log (это, например) ... –

ответ

3

Похоже, что разумный подход ко мне в себе - но требование явно указать this является лишь частью того, как работает язык вокруг методов расширения. Я подозреваю, что это делает аспекты спецификации языка более чистыми, и это требование достаточно редко (и обходной путь достаточно прост), что было сочтено, что лучше пойти с текущим решением, чем сделать вещи более сложными, чтобы избежать пяти символов в относительно редкий сценарий.

Поиск членов для простых имен (раздел 7.6.2 спецификации C# 4) достаточно сложный, не делая его хуже. Не забывайте, что простое имя может ссылаться на параметр типа или типа, а также на метод. Там уже много чего происходит.

Когда я приступаю к работе, я проверю, есть ли какие-либо аннотации вокруг раздела 7.6.5.2 (вызов метода расширения), которые дают «внутреннюю информацию» об этом.


Поразмыслив, он кажется немного странным для лица, выполняющего регистрацию в также хотят войти другие вещи - единственный вид исключения, я бы ожидать, что она увидит, когда будет не удалось выполнить регистрацию, и в этом случае регистрация исключений тоже не удалась.

+0

CoreService в основном получает данные по сети и помещает их в базу данных. Он должен иметь некоторые средства для регистрации своей деятельности. Если некоторые из его операций не работают, он регистрирует это. Если ведение журнала завершается неудачей, оно может игнорировать его (для ведения журнала сети) или само завершение (для регистрации файлов) или независимо от того, что должно быть реализовано при реализации интерфейса. –

+0

@EugeneRyabtsev: Кажется, что он должен * иметь * регистрационный элемент, который знает, как выполнять ведение журнала, а не осуществлять сам интерфейс ведения журнала. Это деталь реализации, а не то, что она должна рекламировать как возможность, которую могут использовать другие, для чего нужны интерфейсы. Отделите проблемы регистрации от «получения данных по сети». Напишите класс, чье задание * sole * регистрируется, а затем создайте экземпляр этого класса, доступный для CoreService. –

+0

Тогда этот член, invokable как logger.Log (...), должен быть полиморфным классом для повторного использования всего кода журнала (...), и я должен сделать потомком для каждого конкретного случая того, что я хочу зарегистрировать и как фильтровать вкл/выкл (или сделать его достаточно большим и общим в первую очередь). Возможно, конечно. Раньше я реализовал такую ​​вещь как множественное наследование на C++, чтобы класс мог реализовать и зарегистрировать свою деятельность и быть в значительной степени автономным, мыслительные интерфейсы находятся как можно ближе. –

Смежные вопросы