如何使用Generics修复这个非常简单的.NET代码来返回强类型结果?

时间:2016-09-03 13:03:08

标签: c# .net generics covariance contravariance

注意:exists in this .NET Fiddle下方的所有代码。

我很难(再次)试图理解泛型/协方差/逆变。 :(

它杀了我 - 所以请善待我。

所以,我有这个虚构的宠物店,我试图轻松在我们的宠物库存中搜索宠物

主要搜索类SearchMagic是我所有的格雷夫。我试图说出以下内容:

var pet = searchMagic.SearchForAPet("Fido");它将......在这种情况下返回一个Dog即Fido。

现在,踢球者是我实施班级SearchMagic的方式。这是智能首先搜索Cat,然后是Dog的地方。问题是,我似乎无法找到一种方法来返回猫或狗实例,如果找到了。它一直在抱怨Cannot implicitly convert...

我一直试图对代码说:至少,我需要返回SearchResult<IAnimal>。因此,如果那是具体的CatDog,那就太棒了。否则,为null 。然后,对于调用该方法并获取返回结果的代码,我可以对该结果执行的唯一事情是SearchResult<IAnimal>中定义的任何内容。因此,如果我的Cat实例具有某些特定于cat的属性或方法,那么运气不好,我无法在result上调用它们,因为结果是SearchResult<IAnimal>且仅{ {1}}东西暴露出来。

这里是代码,其中一些注释为INLINE,以显示错误发生的位置......

请给我看ze代码。

IAnimal

2 个答案:

答案 0 :(得分:2)

Here's one way of doing it

如果您希望SearchForAPet方法能够返回&#34;搜索结果&#34;这可能是一个&#34;狗搜索结果&#34;或者一个&#34; cat搜索结果&#34;,它需要返回一个协变接口,而不是具体类型:

public interface ISearchResult<out TAnimal> where TAnimal: IAnimal
{
    TAnimal Pet { get; }
    decimal Price { get; }
}

public class SearchResult<TAnimal> : ISearchResult<TAnimal> where TAnimal : IAnimal
{
    public TAnimal Pet { get; set; }
    public decimal Price { get; set; }
}

...

public ISearchResult<IAnimal> SearchForAPet(string query)
{
    ...
}

答案 1 :(得分:0)

没有找到任何其他方法来保持结构的完整性。您需要以下内容来获取您的SearchResult:

public interface ISearchResult<out TAnimal> where TAnimal : IAnimal
{
    TAnimal Pet { get; }
    decimal Price { get; }
}

在任何情况下,如果您想退出out,您需要在返回时进行相应的投射。

原因是:

这看起来像另一个经典的协方差,逆变和不变性问题。根据{{​​3}},您可以使用可以使您使用比最初指定的派生类型更多的派生类型,反之亦然,但是您可以预期这样做:

public class Program
{      
    public static void Main()
    {
        List<Derived> dlist = new List<Derived>();
        List<Base> bIEnum = dlist;
    }
}

但是你可以:

public class Program
{  
    public static void Main()
    {
        List<Derived> dlist = new List<Derived>();
        IEnumerable<Base> bIEnum = dlist;
    }
}

因此,拥有ISearchResult或ISearchResult是您最好的选择