Я смотрю на способы улучшить непротиворечивость, краткость и удобочитаемость некоторого кода в приложении, я продолжаю работать. Стартовый код выглядел примерно так:
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);
}
Это не совсем то, что вы просили, но, возможно, этого будет достаточно.
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
}
}
Почему бы не сделать что-то более идоматичное, где вы могли бы использовать общие ограничения для обеспечения соблюдения правил:
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
может сбить с толку. Кроме того, для потребителей библиотеки неочевидно, что это способ "подписки" - если только они не видели пример такого кода.
Вы, вероятно, сможете приблизиться к расширению 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);