我有以下方法:
public static TEventInvocatorParameters Until <TEventInvocatorParameters, TEventArgs>(this TEventInvocatorParameters p, Func<TEventArgs, bool> breakCond) where TEventInvocatorParameters : EventInvocatorParameters<TEventArgs> where TEventArgs : EventArgs { p.BreakCondition = breakCond; return p; }
而这个班
public class EventInvocatorParameters<T> where T : EventArgs { public Func<T, bool> BreakCondition { get; set; } // Other properties used below omitted for brevity. }
现在,我遇到以下问题:
string
new EventInvocatorParameters<EventArgs>(EventABC).Until(e => false);
我不能使用像这样的泛型类型参数吗?您将如何解决这个问题? 要点:我需要这两个通用参数,因为我需要返回调用此扩展方法的相同类型。
广阔的画面(回答问题不是必须的!): 我正在尝试创建一个流畅的界面来调用事件。基础是此静态类:
public static class Fire { public static void Event<TEventArgs>( ConfiguredEventInvocatorParameters<TEventArgs> parameters) where TEventArgs : EventArgs { if (parameters.EventHandler == null) { return; } var sender = parameters.Sender; var eventArgs = parameters.EventArgs; var breakCondition = parameters.BreakCondition; foreach (EventHandler<TEventArgs> @delegate in parameters.EventHandler.GetInvocationList()) { try { @delegate(sender, eventArgs); if (breakCondition(eventArgs)) { break; } } catch (Exception e) { var exceptionHandler = parameters.ExceptionHandler; if (!exceptionHandler(e)) { throw; } } } } }
为确保只能使用完全配置的参数调用此方法,它仅接受ConfiguredEventInvocatorParameters<T>从派生的EventInvocatorParameters<T>:
ConfiguredEventInvocatorParameters<T>
EventInvocatorParameters<T>
public class ConfiguredEventInvocatorParameters<T> : EventInvocatorParameters<T> where T : EventArgs { public ConfiguredEventInvocatorParameters( EventInvocatorParameters<T> parameters, object sender, T eventArgs) : base(parameters) { EventArgs = eventArgs; Sender = sender; } public T EventArgs { get; private set; } public object Sender { get; private set; } }
以下是有效的调用:
Fire.Event(EventName.With(sender, eventArgs)); Fire.Event(EventName.With(sender, eventArgs).Until(e => e.Cancel)); Fire.Event(EventName.Until(e => e.Cancel).With(sender, eventArgs));
以下内容将无效:
// no sender or eventArgs have been specified, i.e. missing call to With(...) Fire.Event(EventName.Until(e => e.Cancel));
为了使这项工作有效,存在名为的扩展方法With,它们可以接受a EventHandler<TEventArgs或a TEventInvocatorParameters并返回a ConfiguredEventInvocatorParameters<TEventArgs>。Withnow 之后的所有调用也都需要返回type ConfiguredEventInvocatorParameters<TEventArgs>,否则有效调用的第二个示例(Until结尾为)将不起作用。 如果您总体上对API有任何想法,请告诉我。但是,我要避免以下三件事:
With
EventHandler<TEventArgs
TEventInvocatorParameters
ConfiguredEventInvocatorParameters<TEventArgs>
Until
EventName.With(...).Until(...).Fire()
Do
Fire(EventName).With(...).Until(...).Do();
对于感兴趣的任何人,到目前为止,我已经使用通用类层次结构解决了原始问题(流事件调用API)。这基本上是Hightechrider对类固醇的回答。
public abstract class EventInvocatorParametersBase <TEventInvocatorParameters, TEventArgs> where TEventArgs : EventArgs where TEventInvocatorParameters : EventInvocatorParametersBase<TEventInvocatorParameters, TEventArgs> { protected EventInvocatorParametersBase( EventHandler<TEventArgs> eventHandler, Func<Exception, bool> exceptionHandler, Func<TEventArgs, bool> breakCondition) { EventHandler = eventHandler; ExceptionHandler = exceptionHandler; BreakCondition = breakCondition; } protected EventInvocatorParametersBase( EventHandler<TEventArgs> eventHandler) : this(eventHandler, e => false, e => false) { } public Func<TEventArgs, bool> BreakCondition { get; set; } public EventHandler<TEventArgs> EventHandler { get; set; } public Func<Exception, bool> ExceptionHandler { get; set; } public TEventInvocatorParameters Until( Func<TEventArgs, bool> breakCondition) { BreakCondition = breakCondition; return (TEventInvocatorParameters)this; } public TEventInvocatorParameters WithExceptionHandler( Func<Exception, bool> exceptionHandler) { ExceptionHandler = exceptionHandler; return (TEventInvocatorParameters)this; } public ConfiguredEventInvocatorParameters<TEventArgs> With( object sender, TEventArgs eventArgs) { return new ConfiguredEventInvocatorParameters<TEventArgs>( EventHandler, ExceptionHandler, BreakCondition, sender, eventArgs); } } public class EventInvocatorParameters<T> : EventInvocatorParametersBase<EventInvocatorParameters<T>, T> where T : EventArgs { public EventInvocatorParameters(EventHandler<T> eventHandler) : base(eventHandler) { } } public class ConfiguredEventInvocatorParameters<T> : EventInvocatorParametersBase<ConfiguredEventInvocatorParameters<T>, T> where T : EventArgs { public ConfiguredEventInvocatorParameters( EventHandler<T> eventHandler, Func<Exception, bool> exceptionHandler, Func<T, bool> breakCondition, object sender, T eventArgs) : base(eventHandler, exceptionHandler, breakCondition) { EventArgs = eventArgs; Sender = sender; } public ConfiguredEventInvocatorParameters(EventHandler<T> eventHandler, object sender, T eventArgs) : this(eventHandler, e => false, e => false, sender, eventArgs) { } public T EventArgs { get; private set; } public object Sender { get; private set; } } public static class EventExtensions { public static EventInvocatorParameters<TEventArgs> Until<TEventArgs>( this EventHandler<TEventArgs> eventHandler, Func<TEventArgs, bool> breakCondition) where TEventArgs : EventArgs { return new EventInvocatorParameters<TEventArgs>(eventHandler). Until(breakCondition); } public static EventInvocatorParameters<TEventArgs> WithExceptionHandler<TEventArgs>( this EventHandler<TEventArgs> eventHandler, Func<Exception, bool> exceptionHandler) where TEventArgs : EventArgs { return new EventInvocatorParameters<TEventArgs>(eventHandler). WithExceptionHandler(exceptionHandler); } public static ConfiguredEventInvocatorParameters<TEventArgs> With<TEventArgs>( this EventHandler<TEventArgs> eventHandler, object sender, TEventArgs eventArgs) where TEventArgs : EventArgs { return new ConfiguredEventInvocatorParameters<TEventArgs>( eventHandler, sender, eventArgs); } }
这使您可以编写如下代码:
Fire.Event(EventName.WithExceptionHandler(e => false) .Until(e => false).With(this, EventArgs.Empty)); Fire.Event(EventName.With(this, EventArgs.Empty)); Fire.Event(EventName.WithExceptionHandler(e => false) .With(this, EventArgs.Empty).Until(e => false)); Fire.Event(EventName.With(this, EventArgs.Empty) .WithExceptionHandler(e => false).Until(e => false));
但这不允许您编写此代码,因为未提供所有必需的信息(eventArgs和sender):
Fire.Event(EventName.Until(e => false)); Fire.Event(EventName);