我已经为我的存储库创建了这个界面。
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,它指定这不应该工作。
引用类型支持泛型类型参数中的协方差和反向方差,但值类型不支持它们。
我创建的类如下所示
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,我可以传递任何类型,因为它仍然是泛型的。
这可能显示了对反方差和协方差缺乏理解,但这让我有点困惑。
发布于 2013-08-07 12:08:52
协方差与反方差在值类型上没有多大意义,因为它们都是密封的。虽然从文档中还不清楚,但是使用struct作为协/反变体类型是有效的,但它并不总是有用的。您所引用的文档很可能指的是以下内容无效:
public struct MyStruct<in T>反方差意味着您可以执行如下示例:
IRepository<string, Base> b = //something
IRepository<string, Derived> d = b;由于没有从int派生出来的东西,所以可以使用IRepository<string, int>,但只能作为IRepository<string, int>使用。
协方差意味着你可以做相反的事情,例如IEnumerable<T>是out T,它是协变的。您可以执行以下操作:
IEnumerable<Derived> d = //something
IEnumerable<Base> b = d;如果您试图将TKey和T限制为classes (引用类型),则应该包括第二个限制:
public interface IRepository<T, in TKey>
where T : class
where TKey : class发布于 2013-08-07 12:13:03
实际上,您忽略了协方差和反向方差的全部要点:-)这是关于能够将泛型类型的变量分配给同一泛型类型的另一个变量,但具有与源中使用的变量相关的不同泛型类型参数。
根据泛型类型参数是协变量还是反变体,允许进行不同的赋值。
假设以下接口:
public interface IRepository<in T>
{
void Save(T value);
}此外,假设以下接口以及实现该接口的值类型和引用类型:
public interface IBar
{
}
public struct BarValueType : IBar
{
}
public class BarReferenceType : IBar
{
}最后,假设有两个变量:
IRepository<BarReferenceType> referenceTypeRepository;
IRepository<BarValueType> valueTypeRepository;反方差现在意味着您可以将IRepository<IBar>的一个实例分配给变量referenceTypeRepository,因为BarReferenceType实现了IBar。
您引用的MSDN部分仅仅意味着将IRepository<IBar>实例分配给valueTypeRepository是不合法的,尽管BarValueType也实现了IBar。
发布于 2013-08-07 12:15:29
使用值类型实现接口没有问题。例如,只有在试图将IRepository<Project, object>分配给IRepository<Project, int>时才会收到错误。在下面的代码中,最后一个赋值将不会编译:
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;
}
}https://stackoverflow.com/questions/18102730
复制相似问题