无法将通用接口添加到具有相同约束的列表
Can't add generic Interface to List with same constraint
我正在与泛型作斗争,我真的不知道我做错了什么。
这是我的例子:
public class Repository // Base-class for all repositories
{
public virtual int GetStatus()
{
return 0;
}
}
Repository
只是一个基础 class.
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];
}
}
CarCache
派生自基础 class CarRepository
以便可以重写这些方法。它还实现了 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
添加到方法中,因此添加了该类型的项目
到 ICache<Repository>
的列表应该有效。这是相同的约束。
这里有什么问题?
一种解决方案是使 ICache<TRepo>
协变。
您需要使 TRepo Repository
get
-仅符合协变限制:
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
}
// ...
}
或者您可以使 setter private
允许其他实现方法 class 设置值:
public class CarCache : CarRepository, ICache<CarRepository>
{
public CarRepository Repository { get; private set; }
// ...
void SetRepository(CarRepository repo)
{
this.Repository = repo;
}
}
我正在与泛型作斗争,我真的不知道我做错了什么。
这是我的例子:
public class Repository // Base-class for all repositories
{
public virtual int GetStatus()
{
return 0;
}
}
Repository
只是一个基础 class.
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];
}
}
CarCache
派生自基础 class CarRepository
以便可以重写这些方法。它还实现了 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
添加到方法中,因此添加了该类型的项目
到 ICache<Repository>
的列表应该有效。这是相同的约束。
这里有什么问题?
一种解决方案是使 ICache<TRepo>
协变。
您需要使 TRepo Repository
get
-仅符合协变限制:
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
}
// ...
}
或者您可以使 setter private
允许其他实现方法 class 设置值:
public class CarCache : CarRepository, ICache<CarRepository>
{
public CarRepository Repository { get; private set; }
// ...
void SetRepository(CarRepository repo)
{
this.Repository = repo;
}
}