2010-06-25 3 views
6

Я ищу способы улучшить согласованность, краткость и удобочитаемость некоторого кода в приложении, над которым я работаю. Стартовый код выглядел примерно так:C# метод расширения по типу с аргументом общего типа

context.GetGraphType<Bar>().Subscribe<Fizz>(
    (instance, evt) => e.Execute((Bar)instance.Instance) 
); 

Существует несколько идентичных строк кода, как указано выше. Я хотел переписать его выглядеть примерно так:

typeof(Bar).SubscribeTo<Fizz>(context); 

С одной стороны, это позволило бы мне воспользоваться формализациями то, что уже стала неформальной конвенцией. Кроме того, я надеялся, что теперь он будет читать что-то вроде «бар, подписывается на событие fizz в данном контексте», а не «контекст получает тип бара и подписывается на fizz, а затем делает некоторые вещи». Я думаю, что поток лучше, и сотрудник, которого я спросил, согласился.

Я начал реализовывать это как метод расширения. Чтобы выполнить вышеизложенное, я хотел использовать абстрактный базовый класс для типа события, поэтому Fizz будет Event<T>. Это означало бы, что аргумент родового типа для метода расширения должен быть ограничен типом того типа, к которому вызывается метод расширения. Итак, для приведенного выше примера Fizz должен быть типа Event<Bar>.

Возможно ли это? В то же время я пошел с альтернативным решением, но мне все же интересно, если это можно сделать. Другие предложения приветствуются.

Спасибо!

Редактировать # 1: Чтобы быть ясным, я понимаю, что могу использовать дополнительный параметр типа, но я ищу способы избежать этого, если это возможно.

Редактировать # 2: Я думаю, что я собираюсь пойти с небольшим изменением принятого ответа, так как он не соответствует 100% моему сценарию. Суть в том, что общий статический класс можно использовать вместо метода расширения для выполнения моей цели. Спасибо dss539!

Обновить код (может быть опечаток, так как я делаю это на лету):

public class Bar { } 

public class Event<TSubscriber> 
{ 
    public abstract void Execute(TSubscriber source); 
} 

public class Fizz : Event<Bar> 
{ 
    public override void Execute(Bar bar) 
    { 
     // respond to event 
    } 
} 

public class Context { } 

public static class ForType<TSubscriber> 
{ 
    public static void SubscribeTo<TEvent>(Context context) 
     where TEvent : Event<TSubscriber> 
    { 
     context.GetType<TSubscriber>().Subscribe<TEvent>(
      (evt, args) => evt.Execute((TSubscriber)args.Source)); 
    } 
} 

public static void Run() 
{ 
    ForType<Bar>.SubscribeTo<Fizz>(context); 
} 
+1

Я не совсем понимаю ваш вопрос. Как выглядит ваша существующая подпись метода? 'Подписка (этот тип типа, действие )'? Если вы покажете, что у вас есть (или эквивалент), это может помочь объяснить. – dss539

+0

Я думаю, что у меня была аналогичная проблема с дизайном некоторое время назад. Удачи :) – leppie

+0

@ dss539 Это будет больше похоже на подписку (этот тип типа, контекст ctx). Проблема в том, что нет способа (что я знаю), чтобы ограничить T типом Event . –

ответ

6

Это не совсем, как вы просили, но, возможно, это будет достаточно.

internal class Program 
{ 
    static void Main(string[] args) 
    { 
     var fizzHandler = new Fizz(); 
     var context = new Context(); 
     Handle<Bar>.With(fizzHandler, context); 
    } 
} 
public class Bar { } 
public class Event<T> { } 
public class Fizz : Event<Bar> { } 
public class Context { }; 
public static class Handle<T> 
{ 
    public static void With(Event<T> e, Context c) 
    { 
     //do your stuff 
    } 
} 
+0

Это именно то, что я искал. Это позволяет мне выполнить мою первоначальную цель читаемости, не минуя компилятор. Благодаря! –

+0

@ Брайан - рад, что я мог бы помочь :) – dss539

4

Почему бы не сделать что-то немного больше idomatic, где вы могли бы использовать общие ограничения для обеспечения соблюдения правил:

public static class SubscriptionManager 
{ 
    public static void SubsribeTo<TSub,TEvent>(Context context) 
     where TEvent : Event<TSub> 
    { 
     /// you code... 
    } 
} 

призывы будет выглядеть так:

SubscriptionManager.SubsribeTo<Bar,Fizz>(context); 

ограничение where TEvent : Event<TSub> обеспечивает взаимосвязь между выбранным событием и типом подписки. В моей книге также предпочтительнее использовать метод расширения класса Type - потому что это имеет тенденцию загромождать intellisense. Type используется во многих ситуациях, и наличие ложных методов появляется в Intellisense во всех экземплярах Type, как правило, сбивает с толку. Для потребителей библиотеки также неочевидно, что это способ «подписаться» - если только они не видели пример кода.

+0

Спасибо за ваш ответ! Я понимаю, что ограничение может применяться таким образом (см. Выше edit). Ваше предложение близко к тому, которое я рассматривал, но предпочитаю метод расширения. Я понимаю отвращение к методам расширения в классе типа Type, но метод локализуется в один класс, который обрабатывает подписки. Кроме того, это не библиотечный метод, который будет потребляться другими. –

0

Вы можете, вероятно, подобраться расширения System.Type (иметь typeof(T).) и добавить метод (расширение) в контексте, преобразующий тип .NET для вашего внутреннего представления типа (то же самое, возвращаемый GetGraphType).

static class Ext { 

    public static TypeofTypeofBar GetGraphTypeFromDotNetType(this Context ctx, Type t) { 
     return __something(t); 
    } 

    public static void SubscribeTo<F, E>(this Type type, Context ctx, E e) 
     where E: Event<T> { 
     context.GetGraphTypeFromDotNetType(type).Subscribe<F>(a); 
    } 

} 

...

typeof(Bar).SubscribeTo(context, action); 
+0

Эй, Мау, так получилось, что описанный вами метод уже существует. Я немного запутался в параметрах типа в вашем примере. Возможно, вы имели в виду "where E: Event "? Если бы это было так, мне не нужно было бы передавать аргумент «событие», такого типа было бы достаточно (на самом деле я не смог бы предоставить экземпляр события). Однако, похоже, что тип абонента все равно должен быть предоставлен как параметр типа. Итак, вы в основном получите «typeof (Bar) .SubscribeTo (ctx)», что является еще одним вариантом, о котором я не волнуюсь. Спасибо за предложение! –

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