Метод расширения C # для типа с аргументом общего типа - PullRequest
6 голосов
/ 25 июня 2010

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

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

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

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

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

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

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

Спасибо!

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

Правка # 2: Я думаю, что я собираюсь пойти с небольшим изменением принятого ответа, так как он не соответствует 100% с моим сценарием.Суть в том, что универсальный статический класс может быть использован вместо метода расширения Type для достижения моей цели.Спасибо 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);
}

Ответы [ 3 ]

7 голосов
/ 01 июля 2010

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

4 голосов
/ 25 июня 2010

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

 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 голосов
/ 25 июня 2010

Вы, вероятно, можете приблизиться к расширению System.Type (чтобы иметь typeof(T).) и добавлению метода (extension) в контекст, который преобразует тип .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);
...