在接口的实现中隐藏类型参数

时间:2013-10-17 19:33:20

标签: c# generics polymorphism

给出以下界面:

public interface IContext {
    TOutput get<TInput, TOutput>(TInput command);
}

以下实施:

public class DbContext: IContext {}

public class Repository {
    private readonly IContext _context;

    public Repository(IContext context) {...}

    public IDto get(int id) {
        var data = _context.get<IThis, IThat>(id)
        //map data to dto and return
    }
}

由于我将IContext依赖项传递给Repository类,我不希望接口上有类型参数,因为它会锁定我使用IContext的显式实现。是什么样的界面静音?

鉴于我在IContext界面上没有类型参数的限制,如何实施IContext以便我可以在我的_context.get(...)类中调用Repository而不是{ {1}}?

换句话说,我希望实现_context.get<IThis, IThat>(...)(在此示例中为IContext)来定义DBContext的类型参数,以便在实际调用该方法时调用者不需要知道要传递的类型参数。

更新

我正在尝试解决的问题是允许将任何类型的get()传递到存储库。如果我在接口上有类级别类型参数,那么我仅限于IContext的实现,这是不理想的。

2 个答案:

答案 0 :(得分:1)

如果IContext对象有get函数可以接受任何对象作为输入并提供任何对象作为输出而不是泛型,那么接口方法应该只使用{{ 1}}:

object

(接口的实现者可以暴露强类型方法,并为该方法使用显式接口实现。

另一种可能性是,在接受public interface IContext { object get(object command); } 对象时,您的IContext对象知道该方法的签名应该是什么。在这种情况下,你想要使接口,而不是它的方法,通用:

IContext

这当然意味着你不能拥有各种不同类型public interface IContext<TInput, TOutput> { TOutput get(TInput command); } 对象的对象集合;他们需要共享签名。接受或返回IContext对象的方法需要知道输入/输出在编译时应该是什么类型,或者它们本身需要是通用的。

在与您使用界面相关或可能不相关的旁注上,您可以利用您的通用参数的协方差和逆变,这可能有助于您使用界面,也可能没有帮助:

IContext

如果不了解您希望如何实际使用该界面,则不清楚哪种解决方案更好。

答案 1 :(得分:0)

据我了解,您需要通过界面松散耦合进行具体打字。 考虑一下:

public interface ICommand {}

public interface IContextOutput {}

public interface IContext
{
    IContextOutput Get(ICommand input);
}

public abstract class ContextBase<TInput, TOutput> : IContext       
    where TInput : ICommand
    where TOutput : IContextOutput
{
    IContextOutput IContext.Get (ICommand input)
    {
        if (input.GetType () != typeof(TInput))
        {
            throw new ArgumentOutOfRangeException("input");
        }

        return Get((TInput)input);
    }

    protected abstract TOutput Get(TInput command);     
}

然后从抽象类派生所有上下文