首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >反变值类型

反变值类型
EN

Stack Overflow用户
提问于 2013-08-07 11:55:07
回答 4查看 278关注 0票数 4

我已经为我的存储库创建了这个界面。

代码语言:javascript
复制
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);
}

FindSingle方法接受一个ID,该ID将用于搜索主键。通过使用in,我期望只允许将引用类型作为TKey传递。出于好奇,我决定创建一个具体的类,并将其指定为int,这样我就可以看到异常。

我查找了MSDN,它指定这不应该工作。

引用类型支持泛型类型参数中的协方差和反向方差,但值类型不支持它们。

我创建的类如下所示

代码语言:javascript
复制
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();
    }
}

为什么我在将TKey指定为值类型时没有得到一个异常?另外,如果我从参数中删除了in,那么我丢失了什么?MSDN文档说,逆方差允许使用派生较少的类型,但通过删除in,我可以传递任何类型,因为它仍然是泛型的。

这可能显示了对反方差和协方差缺乏理解,但这让我有点困惑。

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2013-08-07 12:08:52

协方差与反方差在值类型上没有多大意义,因为它们都是密封的。虽然从文档中还不清楚,但是使用struct作为协/反变体类型是有效的,但它并不总是有用的。您所引用的文档很可能指的是以下内容无效:

代码语言:javascript
复制
public struct MyStruct<in T>

反方差意味着您可以执行如下示例:

代码语言:javascript
复制
IRepository<string, Base> b = //something
IRepository<string, Derived> d = b;

由于没有从int派生出来的东西,所以可以使用IRepository<string, int>,但只能作为IRepository<string, int>使用。

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

代码语言:javascript
复制
IEnumerable<Derived> d = //something
IEnumerable<Base> b = d;

如果您试图将TKeyT限制为classes (引用类型),则应该包括第二个限制:

代码语言:javascript
复制
public interface IRepository<T, in TKey>
    where T : class
    where TKey : class
票数 6
EN

Stack Overflow用户

发布于 2013-08-07 12:13:03

实际上,您忽略了协方差和反向方差的全部要点:-)这是关于能够将泛型类型的变量分配给同一泛型类型的另一个变量,但具有与源中使用的变量相关的不同泛型类型参数。

根据泛型类型参数是协变量还是反变体,允许进行不同的赋值。

假设以下接口:

代码语言:javascript
复制
public interface IRepository<in T>
{
    void Save(T value);
}

此外,假设以下接口以及实现该接口的值类型和引用类型:

代码语言:javascript
复制
public interface IBar
{
}

public struct BarValueType : IBar
{
}

public class BarReferenceType : IBar
{
}

最后,假设有两个变量:

代码语言:javascript
复制
IRepository<BarReferenceType> referenceTypeRepository;
IRepository<BarValueType> valueTypeRepository;

反方差现在意味着您可以将IRepository<IBar>的一个实例分配给变量referenceTypeRepository,因为BarReferenceType实现了IBar

您引用的MSDN部分仅仅意味着将IRepository<IBar>实例分配给valueTypeRepository是不合法的,尽管BarValueType也实现了IBar

票数 2
EN

Stack Overflow用户

发布于 2013-08-07 12:15:29

使用值类型实现接口没有问题。例如,只有在试图将IRepository<Project, object>分配给IRepository<Project, int>时才会收到错误。在下面的代码中,最后一个赋值将不会编译:

代码语言:javascript
复制
public interface IContravariant<T, in TKey> where T : class
{
    T FindSingle(TKey id);
}
public class objCV : IContravariant<Project, object>
{
    public Project FindSingle(object id)
    {
        return null;
    }
    public static void test()
    {
        objCV objcv = new objCV();

        IContravariant<Project, Project> projcv;
        IContravariant<Project, int> intcv;

        projcv = objcv;
        intcv = objcv;
    }
}
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/18102730

复制
相关文章

相似问题

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