在接口实现中隐藏类型参数
本文关键字:隐藏 类型参数 实现 接口 | 更新日期: 2023-09-27 18:35:53
给定以下接口:
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
以便我可以在我的 Repository
类中调用_context.get(...)
而不是_context.get<IThis, IThat>(...)
?
所以换句话说,我希望IContext
的实现(在这个例子中DBContext
)来定义get()
的类型参数,以便在实际调用该方法时,调用者不需要知道任何关于要传递的类型参数。
更新
我试图解决的问题是允许将任何类型的IContext
传递到存储库中。如果我在接口上有类级类型参数,那么我只能实现IContext<TThis, TThat>
,这并不理想。
如果一个IContext
对象有一个可以接受任何对象作为输入并提供任何对象作为输出的get
函数很重要,那么提供任何对象作为输出而不是泛型,你的接口方法应该简单地使用object
:
public interface IContext {
object get(object command);
}
(然后,接口的实现者可能会公开一个强类型方法,并对该方法使用显式接口实现。
另一种可能性是,IContext
对象在接受IContext
对象时知道方法的签名应该是什么。 在这种情况下,您可能希望使接口而不是其方法成为通用的:
public interface IContext<TInput, TOutput> {
TOutput get(TInput command);
}
这当然意味着你不能拥有各种不同种类的IContext
对象的集合;它们需要共享一个签名。 接受或返回IContext
对象的方法需要在编译时知道输入/输出应该是什么类型,或者它们本身需要是泛型的。
也可能无关,您可以在通用参数上利用协方差和逆变,这可能有助于也可能无助于您使用接口:
public interface IContext<in TInput, out TOutput>
{
TOutput get(TInput command);
}
如果不了解您希望如何实际使用界面,则不清楚哪个是更好的解决方案。
据我了解,您需要具体类型以及通过接口的松散耦合。考虑一下:
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);
}
然后从抽象类派生所有上下文。