逆变值类型

Jam*_*mes 4 .net c# contravariance

我为我的存储库创建了这个界面.

public interface IRepository<T, in TKey> where T: class
{
    IEnumerable<T> Find(Expression<Func<T, bool>> predicate);
    IEnumerable<T> FindAll();
    T FindSingle(TKey id);
    void Create(T entity);
    void Delete(T entity);
    void Update(T entity);
}
Run Code Online (Sandbox Code Playgroud)

FindSingle方法接受一个I​​D,该ID将用于在主键上进行搜索.通过使用in我期望我只允许传递引用类型TKey.出于好奇,我决定创建一个具体的类并将其指定为int,所以我可以看到异常.

我查了MSDN,它指出这不应该工作

参考类型支持泛型类型参数的协方差和逆变,但值类型不支持它们.

我创建的类看起来像这样

public class ProjectRepository : IRepository<Project,int>
{
    public IEnumerable<Project> Find(Expression<Func<Project, bool>> predicate)
    {
        throw new NotImplementedException();
    }

    public IEnumerable<Project> FindAll()
    {
        throw new NotImplementedException();
    }

    public Project FindSingle(int id)
    {
        throw new NotImplementedException();
    }

    public void Create(Project entity)
    {
        throw new NotImplementedException();
    }

    public void Delete(Project entity)
    {
        throw new NotImplementedException();
    }

    public void Update(Project entity)
    {
        throw new NotImplementedException();
    }
}
Run Code Online (Sandbox Code Playgroud)

为什么我没有在指定TKey为值类型的构建上获得异常?另外,如果我in从参数中删除了我丢失的内容?MSDN文档说逆向允许使用较少派生的类型,但肯定通过删除in我可以传递任何类型,因为它仍然是通用的.

这可能表现出对逆变和协方差的缺乏理解,但它让我有点困惑.

Tim*_* S. 6

协方差和逆变对价值类型没有多大意义,因为它们都是密封的.虽然从文档中不清楚,但使用a struct作为co/contravariant类型是有效的,它并不总是有用.您引用的文档很可能是指以下内容无效:

public struct MyStruct<in T>
Run Code Online (Sandbox Code Playgroud)

逆变法意味着您可以执行以下示例:

IRepository<string, Base> b = //something
IRepository<string, Derived> d = b;
Run Code Online (Sandbox Code Playgroud)

由于没有任何东西可以衍生出来int,你可以使用IRepository<string, int>,但只能作为IRepository<string, int>.

协方差意味着你可以做相反的,例如IEnumerable<T>out T,这是协变的.您可以执行以下操作:

IEnumerable<Derived> d = //something
IEnumerable<Base> b = d;
Run Code Online (Sandbox Code Playgroud)

如果你想限制都TKeyTclassES(引用类型),你应该包括第二限制:

public interface IRepository<T, in TKey>
    where T : class
    where TKey : class
Run Code Online (Sandbox Code Playgroud)