简体   繁体   English

两个类型参数之间的等式约束

[英]Equality constraint between two type parameters

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 : 但其中一人已经知道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. 谢谢你的帮助。

If you don't ever plan on using MultiReader as an IReader then why bother making it implement the IReader interface? 如果你不打算将MultiReader用作IReader那么为什么还要打扰它实现IReader接口呢? 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 . 我们的想法是,您可以将引用存储为IReader,并将该对象与实现IReader任何其他类型交替使用。 That doesn't seem to be the case with MultiReader . MultiReader似乎并非如此。

In my opinion, MultiReader should not implement IReader because it seems like you don't intend to use it via the IReader interface. 在我看来, MultiReader不应该实现IReader因为你似乎不打算通过IReader接口使用它。 Be wary of violating the Liskov Substitution Principle . 警惕违反Liskov替代原则

Since IReader<TOut> is contract, there is no way to hide that method. 由于IReader<TOut>是合约,因此无法隐藏该方法。 Interface requires exposing method that meets specified cotnract signature. 接口需要符合指定cotnract签名的公开方法。 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. 这就是为什么你仍然需要在实现中进行强制检查。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM