我有以下问题:
界面:
public interface IReader<TOut>
{
IEnumerable<TOut> GetData(int from, int size);
TOut Read<TKey>(TKey input);
}
然后我有几个这样的实现:
public class ConcreteReader<TOut> : IReader<TOut>
{
private IReader<TOut> parentReader;
public IEnumerable<TOut> GetData(int from, int size)
{
// do stuff, don't need TKey for this
}
public TOut Read<TKey>(TKey Input)
{
this.parentReader.Read(input);
... // Do my job
return result;
}
}
但其中一人已经知道TKey:
public class MultiReader<TKey, TOut> : IReader<TOut>
{
public IEnumerable<TOut> GetData(int from, int size)
{
// do stuff. need TKey here
}
// this method does the job but it can't be the implementation of IReader<TOut>.Read<TKey>
public TOut Read(TKey input)
{
...
}
// this is the implementation of IReader<TOut>.Read<TKey>
// I would like to enforce TKey == TKey1 but I can't write
// where TKey1 : TKey because the constraint would have to be on IReader interface
public TOut Read<TKey1>(TKey1 input)
{
...
}
}
基于另一篇文章,我能写出:
public TOut Read<TKey1>(TKey1 input)
{
if (input is TKey)
{
object objectId = (object)input;
TKey keyId = (TKey)objectId;
return this.Read(keyId);
}
throw new InvalidOperationException();
}
但我发现它非常难看。
还有更好的选择吗? 我希望这个解释很清楚。
感谢您的帮助。
答案 0 :(得分:2)
如果您不打算将MultiReader
用作IReader
,那么为什么还要打扰它实现IReader
界面呢?我们的想法是,您可以将引用存储为IReader,并将该对象与实现IReader
的任何其他类型交替使用。 MultiReader
似乎不是这种情况。
在我看来,MultiReader
不应该实现IReader
,因为您似乎不打算通过IReader
界面使用它。警惕违反Liskov Substitution Principle。
答案 1 :(得分:1)
由于IReader<TOut>
是契约,因此无法隐藏该方法。接口需要符合指定cotnract签名的公开方法。但是......你可以通过显式接口实现来做一些小技巧:
public class MultiReader<TKey, TOut> : IReader<TOut>
{
public TOut Read(TKey input)
{
return ((IReader<TOut>)this).Read<TKey>(input);
}
TOut IReader<TOut>.Read<TKey1>(TKey1 input)
{
if (input is TKey)
{
object objectId = (object)input;
TKey keyId = (TKey)objectId;
return this.Read(keyId);
}
throw new InvalidOperationException();
}
}
然后:
var mr = new MultiReader<string, string>();
var test = mr.Read("someKey"); //OK
var test2 = mr.Read<int>(1); //compile-time error
但你仍然可以
var mr = new MultiReader<string, string>();
var test = mr.Read("someKey"); //OK
var test2 = ((IReader<string>)mr).Read<int>(1); //that is ok,
//we use contract - we cannot prevent this
这就是为什么你仍然需要在实现中进行强制检查。