Dan*_*rth 12 .net c# generics extension-methods fluent-interface
我有以下方法:
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;
}
Run Code Online (Sandbox Code Playgroud)
而这堂课
public class EventInvocatorParameters<T>
where T : EventArgs
{
public Func<T, bool> BreakCondition { get; set; }
// Other properties used below omitted for brevity.
}
Run Code Online (Sandbox Code Playgroud)
现在,我有以下问题:
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;
}
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
要确保只能使用完全配置的参数调用此方法,它只接受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; }
}
Run Code Online (Sandbox Code Playgroud)
以下是有效的电话:
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));
Run Code Online (Sandbox Code Playgroud)
以下内容无效:
// no sender or eventArgs have been specified, i.e. missing call to With(...)
Fire.Event(EventName.Until(e => e.Cancel));
Run Code Online (Sandbox Code Playgroud)
为了使这项工作,存在名为的扩展方法With
,它接受a EventHandler<TEventArgs
或a TEventInvocatorParameters
并返回a ConfiguredEventInvocatorParameters<TEventArgs>
.With
现在之后的所有调用也需要返回类型ConfiguredEventInvocatorParameters<TEventArgs>
,否则有效调用的第二个示例(Until
最后一个)将不起作用.
如果您对API有任何想法,请告诉我.但是,我想避免以下三件事:
EventName.With(...).Until(...).Fire()
Do
方法开始:Fire(EventName).With(...).Until(...).Do();
Eri*_*ert 19
泛型方法的类型推断故意并没有使从限制任何扣减.相反,从参数和形式参数中进行推导,然后根据约束检查推导出的类型参数.
有关约束和方法签名的一些设计问题的详细讨论,包括几十个人告诉我,我认为现有设计是明智的是错误的,请参阅我关于这个主题的文章:
对于任何感兴趣的人,目前,我使用通用类层次结构解决了最初的问题(流畅的事件调用 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);
}
}
Run Code Online (Sandbox Code Playgroud)
这允许您编写如下代码:
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));
Run Code Online (Sandbox Code Playgroud)
但它不允许您编写此内容,因为并未提供所有必要的信息(eventArgs 和发件人):
Fire.Event(EventName.Until(e => false));
Fire.Event(EventName);
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
2889 次 |
最近记录: |