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



我在泛型方面很吃力,不知道自己做错了什么。

这是我的例子:

public class Repository // Base-class for all repositories
{
public virtual int GetStatus()
{
return 0;
}
}

Repository只是一个基类。

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简单地提供了与汽车交互的基本方法。

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。你明白了。

这是为了设置。

现在,我想缓存结果。为了保持通用性,我创建了以下结构:

public interface ICache<TRepo> // Basic Cache Interface
where TRepo : Repository
{
TRepo Repository { get; set; }
}
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];
}
}

CCD_ 4从基类CCD_ 5派生以使重写这些方法成为可能。它还实现了ICache<T>,它提供了对实际CarRepository的实现,例如HttpCarRepository

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

public class Manager
{
public List<ICache<Repository>> Caches;
}

我使用Repository作为泛型类型,因为ICache<T>接口将类型约束为Repository

现在的问题是:我有一个方法来添加一个看起来像的缓存

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,所以添加了该类型的项到CCD_ 14的列表应该工作。这是同样的约束。

这里出了什么问题?

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

您需要使TRepo Repositoryget-仅符合协变限制:

public interface ICache<out TRepo> where TRepo : Repository
{
TRepo Repository { get; }
}

只要属性仅通过您的构造函数设置即可:

public class CarCache : CarRepository, ICache<CarRepository> 
{
public CarRepository Repository { get; }
public CarCache(CarRepository repo)
{
this.Repository = repo; // Fine to set Repository here
}
// ...
}

或者,您可以使setterprivate允许实现类的其他方法设置值:

public class CarCache : CarRepository, ICache<CarRepository> 
{
public CarRepository Repository { get; private set; }
// ...

void SetRepository(CarRepository repo)
{
this.Repository = repo;
}
}

最新更新