Reputation: 63
I have the following issue :
interface :
public interface IReader<TOut>
{
IEnumerable<TOut> GetData(int from, int size);
TOut Read<TKey>(TKey input);
}
then I have several implementations like this one :
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;
}
}
but one of them already knows 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)
{
...
}
}
Based on another post I was able to write :
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();
}
but I find it very ugly.
Any better option? I hope this explanation is clear enough.
Thanks for your help.
Upvotes: 3
Views: 71
Reputation: 19526
If you don't ever plan on using MultiReader
as an IReader
then why bother making it implement the IReader
interface? The idea is that you'd be able to store the reference as an IReader and use the object interchangeably with any other type that implements IReader
. That doesn't seem to be the case with MultiReader
.
In my opinion, MultiReader
should not implement IReader
because it seems like you don't intend to use it via the IReader
interface. Be wary of violating the Liskov Substitution Principle.
Upvotes: 2
Reputation: 3383
Since IReader<TOut>
is contract, there is no way to hide that method. Interface requires exposing method that meets specified cotnract signature. But.. you can do a little trick here with explicit interface implementation:
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();
}
}
Then:
var mr = new MultiReader<string, string>();
var test = mr.Read("someKey"); //OK
var test2 = mr.Read<int>(1); //compile-time error
But you can still do
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
So that is why you still need cast-check in implementation.
Upvotes: 1