Метод расширения C# на типе с общим аргументом типа

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

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

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

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

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

Я начал реализовывать это как дополнительный метод. Для выполнения вышеупомянутого, я хотел использовать абстрактный универсальный базовый класс для типа события, таким образом, 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);
}
6
задан Bryan Matthews 3 May 2019 в 20:20
поделиться

3 ответа

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

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
    }
}
7
ответ дан 9 December 2019 в 22:28
поделиться

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

 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 обеспечивает желаемую связь между событием и типом подписки. В моей книге оно также предпочтительнее метода расширения класса Type - потому что это имеет тенденцию загромождать intellisense. Type используется во многих ситуациях, и появление в Intellisense навязчивых методов для всех экземпляров Type может сбить с толку. Кроме того, для потребителей библиотеки неочевидно, что это способ "подписки" - если только они не видели пример такого кода.

4
ответ дан 9 December 2019 в 22:28
поделиться

Вы, вероятно, сможете приблизиться к расширению 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
ответ дан 9 December 2019 в 22:28
поделиться