假设我有以下扩展方法:
public static TContext Timeout<TContext>(this TContext context, TimeSpan timeout)
where TContext : IContext
{
// ...
}
这种扩展方法允许我实现不变性并保留调用类型:
ITransactionalContext c = // ...;
c = c.Timeout(TimeSpan.FromSeconds(5));
但是,如何通过界面实现这一目标?
例如,这将不相同:
public interface IContext
{
IContext Timeout(TimeSpan timeout);
}
因为我的代码示例无法编译。
ITransactionalContext c = // ...;
c = c.Timeout(TimeSpan.FromSeconds(5)); // <-- An IContext is returned. Cannot assign to variable.
我可以将接口的上下文类型指定为通用参数:
public interface IContext
{
}
public interface IContext<TContext> : IContext
where TContext : IContext
{
TContext Timeout(TimeSpan timeout);
}
public interface ITransactionalContext : IContext<ITransactionalContext>
{
}
但这似乎并不好看。
此外,如果ITransactionalContext
需要更多参数,那该怎么办:
public interface ITransactionalContext<TTransaction, TEntity>
: IContext<ITransactionalContext<TTransaction, TEntity>>
{
}
这是一些仿制药混乱。
是否有更简洁的方法来实现扩展方法的目标?
答案 0 :(得分:1)
使用扩展方法的解决方案是理想的,因为它依赖于编译器推断TContext
的能力。然而,它的主要缺点是它没有IContext
类提供它们自己的Timeout(TimeSpan)
方法实现。实际上,克隆过程的控制取自IContext
实现。
如果要在IContext
实现中保持对克隆的控制,请将接口方法和扩展方法组合在一起,如下所示:
interface IContext {
... // Your methods
IContext CloneWithTimeout(TimeSpan timeout);
}
...
public static TContext Timeout<TContext>(this TContext context, TimeSpan timeout)
where TContext : IContext
{
return (TContext)context.CloneWithTimeout(timeout);
}
您的用例继续编译,而生成新实例的过程完全由IContext
的实现控制。