如何将此扩展方法转换为接口方法

时间:2016-10-11 19:51:07

标签: c# .net generics interface

假设我有以下扩展方法:

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>>
{
}

这是一些仿制药混乱。

是否有更简洁的方法来实现扩展方法的目标?

1 个答案:

答案 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的实现控制。