Contravariant Value Types
我已经为我的存储库创建了这个接口。
1 2 3 4 5 6 7 8 9 | 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); } |
我查找了msdn,它指定这不应该起作用
Covariance and contravariance in generic type parameters are supported for reference types, but they are not supported for value types.
我创建的类如下所示
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | 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(); } } |
为什么在将
这可能显示出对协方差和协方差的理解不足,但这让我有点困惑。
协方差和反方差在值类型上没有那么有意义,因为它们都是密封的。虽然从文档中不清楚,但是使用
1 | public struct MyStruct<in T> |
反向变化意味着你可以做如下的事情:
1 2 | IRepository<string, Base> b = //something IRepository<string, Derived> d = b; |
由于没有来自
协方差意味着你可以做相反的事情,例如,
1 2 | IEnumerable<Derived> d = //something IEnumerable<Base> b = d; |
如果您试图将
1 2 3 | public interface IRepository<T, in TKey> where T : class where TKey : class |
实际上,您缺少了co-和contravariance的整个点:-)这是关于能够将一个泛型类型的变量赋给同一个泛型类型的另一个变量,但具有与源中使用的变量相关的不同的泛型类型参数。根据泛型类型参数是同变量还是反变量,允许不同的赋值。
假设以下接口:
1 2 3 4 | public interface IRepository<in T> { void Save(T value); } |
此外,假定以下接口以及实现它的值类型和引用类型:
1 2 3 4 5 6 7 8 9 10 11 | public interface IBar { } public struct BarValueType : IBar { } public class BarReferenceType : IBar { } |
最后,假设两个变量:
1 2 | IRepository<BarReferenceType> referenceTypeRepository; IRepository<BarValueType> valueTypeRepository; |
相反现在意味着您可以将
使用值类型实现接口没有问题。例如,只有在尝试将
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | 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; } } |
在本文中,他们告诉我们编译器将类型参数视为不变量:
Variance applies only to reference types; if you specify a value type
for a variant type parameter, that type parameter is invariant for the
resulting constructed type.
发件人:http://msdn.microsoft.com/en-us/library/dd799517.aspx