首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >无法将通用接口添加到具有相同约束的列表

无法将通用接口添加到具有相同约束的列表
EN

Stack Overflow用户
提问于 2020-07-17 17:20:48
回答 1查看 68关注 0票数 3

我正在为泛型而苦苦挣扎,并不知道我到底做错了什么。

这是我的例子:

代码语言:javascript
复制
public class Repository // Base-class for all repositories
{
    public virtual int GetStatus()
    {
        return 0;
    }
}

Repository只是一个基类。

代码语言:javascript
复制
public class CarRepository : Repository // base-class for all car repositories
{
    private object dataSource;

    public override int GetStatus()
    {
        return dataSource.GetHashCode(); // dummy
    }

    public virtual int GetPrice(string carName)
    {
        if (carName.Equals("BMW", StringComparison.OrdinalIgnoreCase)) {
            return 100;
        }

        return 50;
    }
}

CarRepository只是提供了与汽车交互的基本方法。

代码语言:javascript
复制
public class HttpCarRepository : CarRepository // loads the car data from REST Api
{
    private dynamic httpClient; // just as an example
    public override int GetStatus()
    {
        return httpClient.IsConnected();
    }

    public override int GetPrice(string carName)
    {
        return httpClient.GetAsync("/rest/car/BMW").Result;
    }
}

还可能有一个从数据库加载数据的DataBaseCarRepository。你说对了。

这就是设置。

现在,我想缓存结果。为了保持它的通用性,我创建了这个结构:

代码语言:javascript
复制
public interface ICache<TRepo> // Basic Cache Interface
    where TRepo : Repository
{
    TRepo Repository { get; set; }
}
代码语言:javascript
复制
public class CarCache : CarRepository, ICache<CarRepository> 
{
    public CarRepository Repository { get; set; }
    private dynamic cache;

    public CarCache(CarRepository repo)
    {
        this.Repository = repo;
    }

    public override int GetPrice(string carName)
    {
        if (!this.cache.Contains(carName)) {
            this.cache.Add(carName, this.Repository.GetPrice(carName));
        }

        return cache[carName];
    }
}

CarCache派生自基类CarRepository,从而可以覆盖这些方法。它还实现了ICache<T>,它提供了对CarRepository的实际实现的引用,比如HttpCarRepository

现在,我想将CarCache添加到缓存列表中。

代码语言:javascript
复制
public class Manager
{
    public List<ICache<Repository>> Caches;
}

我使用Repository作为泛型类型,因为ICache<T>接口将该类型限制为Repository

现在的问题是:我有一个添加缓存的方法,如下所示

代码语言:javascript
复制
static void Add<TCache>(Repository repo)
    where TCache : Repository, ICache<TCache>
{
    ICache<TCache> newEntry = Activator.CreateInstance(typeof(TCache), repo) as ICache<TCache>;
    Caches.Add(newEntry); // Error: Cannot convert from ICache<TCache> to ICache<Repository>
}

这让我很困惑。根据我的理解,这应该是可行的,因为我已经向该方法添加了约束where TCache : Repository,因此向ICache<Repository>列表添加该类型的项应该是可行的。这是相同的约束。

这里有什么问题?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2020-07-17 17:34:14

一种解决方案是使ICache<TRepo>协变。

您需要使TRepo Repository get-only符合协变限制:

代码语言:javascript
复制
public interface ICache<out TRepo> where TRepo : Repository
{
    TRepo Repository { get; }
}

只要该属性仅通过构造函数设置,就可以很好地工作:

代码语言:javascript
复制
public class CarCache : CarRepository, ICache<CarRepository> 
{
    public CarRepository Repository { get; }

    public CarCache(CarRepository repo)
    {
        this.Repository = repo; // Fine to set Repository here
    }

    // ...
}

或者,您可以将设置器设为private,以允许实现类的其他方法设置值:

代码语言:javascript
复制
public class CarCache : CarRepository, ICache<CarRepository> 
{
    public CarRepository Repository { get; private set; }

    // ...
    
    void SetRepository(CarRepository repo)
    {
        this.Repository = repo;
    }
}
票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/62951016

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档