【发布时间】:2011-03-05 11:57:23
【问题描述】:
问题
这是我不久前遇到的,并且能够以某种方式解决它。但现在它又回来了,满足了我的好奇心——我很想得到一个明确的答案。
基本上,我有一个通用的 dgv BaseGridView<T> : DataGridView where T : class。基于BaseGridView 构造的类型(如InvoiceGridView : BaseGridView<Invoice>)稍后在应用程序中使用,以使用BaseGridView 提供的共享功能(如虚拟模式、按钮等)显示不同的业务对象。
现在有必要创建一个引用这些构造类型的用户控件,以控制来自BaseGridView 的一些共享 功能(例如过滤)。因此,我希望在用户控件上创建一个公共属性,使我能够将其附加到 Designer/code 中的任何 BaseGridView:public BaseGridView<T> MyGridView { get; set; }。问题是,它不起作用:-) 编译时,我收到以下消息:
找不到类型或命名空间名称“T”(您是否缺少 using 指令或程序集引用?)
解决方案?
我意识到我可以将共享功能提取到一个接口,将BaseGridView 标记为实现该接口,然后在我的 uesr 控件中引用创建的接口。
但我很好奇是否存在一些神秘的 C# 命令/语法可以帮助我实现我想要的 - 而不会用我并不真正需要的接口污染我的解决方案:-)
编辑:作为参考,我确实尝试了这种无辜的解决方法:BaseGridView<object> MyGridView { get; set; },并且...仍然不是答案:无法将类型“InvoiceGridView”隐式转换为“ BaseGridView.
部分成功(编辑 2)
好的,因为只在接口上支持协方差,所以我承认失败并定义了一个接口(只显示了其中的一部分):
public interface IBaseGridView<out T> where T : class
{
bool ScrollTo(Predicate<T> criteria);
bool ScrollTo(T object);
}
我现在可以将我心爱的 InvoiceGridView 投给 IBaseGridView<object> - 太棒了,我又是一个快乐的男孩了 :-) 然而,第二个 ScrollTo 正在给予我在编译时遇到了麻烦:
无效方差:类型参数“T”必须在“GeParts.Controls.IBaseGridView.ScrollTo(T)”上逆变有效。 'T' 是协变的。
我现在不得不将签名修改为ScrollTo(object o) - 这并不理想,但可以完成工作。令我吃惊的是编译器抱怨第二个ScrollTo 但对第一个很满意。所以似乎不允许传递out T 的实例,但是使用类型本身(例如在Predicate<T> 中)可以吗?好像比较挑剔……
【问题讨论】:
-
你不能把这个共享代码放在所有这些网格的公共基类中吗?
-
在大多数情况下 - 不,因为大多数共享功能需要使用 T - 排序、滚动、过滤。
-
请不要在标题中重复“C#”之类的标签。这就是标签的用途。
标签: c# .net generics interface properties