c# - 无法将通用接口(interface)添加到具有相同约束的列表

标签 c# .net generics interface

我正在与泛型作斗争,我真的不知道我做错了什么。

这是我的例子:

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];
    }
}

CarCache派生自基类 CarRepository使重写方法成为可能。它还实现了 ICache<T>它提供了一个实际的引用 实现CarRepository ,例如 HttpCarRepository .

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

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

我用过 Repository作为通用类型,因为 ICache<T>接口(interface)将类型约束为 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
    }

    // ...
}

或者你可以让二传手private允许实现类的其他方法设置值:

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

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

关于c# - 无法将通用接口(interface)添加到具有相同约束的列表,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62951016/

相关文章:

c# - 在哪里可以找到 C# 的反锐化蒙版?

c# - Socket.Bind 然后连接到 MS Loopback NIC

c# - 强制 C# 方法只传递正参数?

java - Java中使用链表实现的队列

c# - 读取另一个进程使用的文件

c# - 应用(服务)自升级?

c# 为什么 Convert.ToInt16(num) vs ToInt16(num)?

.net - VB.Net WinForms 表单 OnPaint() 透明度刷新

java - 如何获取泛型类型 T 的类实例?

java - 如何在 Java 中使用泛型来使用两个接口(interface)作为参数?