C# 作为属性的非构造泛型(例如List<;T>;) 问题

C# 作为属性的非构造泛型(例如List<;T>;) 问题,c#,.net,generics,interface,properties,C#,.net,Generics,Interface,Properties,这是我不久前遇到的一件事,我能够以某种方式解决它。但现在它回来了,激起了我的好奇心——我很想得到一个明确的答案 基本上,我有一个通用的dgvBaseGridView:DataGridView,其中T:class。基于BaseGridView(例如InvoiceGridView:BaseGridView)的构造类型随后在应用程序中使用BaseGridView提供的共享功能(如虚拟模式、按钮等)来显示不同的业务对象 现在有必要创建一个用户控件,该控件引用那些构造的类型来控制BaseGridView中

这是我不久前遇到的一件事,我能够以某种方式解决它。但现在它回来了,激起了我的好奇心——我很想得到一个明确的答案

基本上,我有一个通用的dgv
BaseGridView:DataGridView,其中T:class
。基于
BaseGridView
(例如
InvoiceGridView:BaseGridView
)的构造类型随后在应用程序中使用
BaseGridView
提供的共享功能(如虚拟模式、按钮等)来显示不同的业务对象

现在有必要创建一个用户控件,该控件引用那些构造的类型来控制
BaseGridView
中的一些共享功能(例如过滤)。因此,我希望在用户控件上创建一个公共属性,使我能够将它附加到设计器/code:
public-BaseGridView-MyGridView{get;set;}
中的任何
BaseGridView
。问题是,它不工作:-)编译时,我得到以下消息:

找不到类型或命名空间名称“T”(是否缺少using指令或程序集引用?)

解决? 我意识到我可以将共享功能提取到一个接口,将
BaseGridView
标记为实现该接口,然后在我的uesr控件中引用创建的接口

但我很好奇,是否存在一些神秘的C#命令/语法可以帮助我实现我想要的——而不会用我并不真正需要的接口污染我的解决方案:-)

EDIT:作为参考,我确实尝试了这个简单的解决方法:
BaseGridView-MyGridView{get;set;}
,并且。。。这仍然不是答案:无法将类型“InvoiceGridView”隐式转换为“BaseGridView”

部分成功(编辑2) 好的,因为协方差只在接口上受支持,所以我承认失败并定义了一个接口(只显示了其中的一部分):

公共接口IBaseGridView其中T:class
{
bool-ScrollTo(谓词标准);
bool-ScrollTo(T对象);
}
我现在可以将我心爱的
InvoiceGridView
投射到一个
IBaseGridView
-上,这真是太棒了,我又是一个快乐的男孩:-)但是,第二个
滚动条给我的编译带来了麻烦:

无效差异:类型参数“T”必须在“GeParts.Controls.IBaseGridView.ScrollTo(T)”上反向有效T’是协变的


我现在必须将签名修改为
ScrollTo(objecto)
——这并不理想,但可以完成任务。令我惊讶的是,编译器抱怨第二个
滚动条
,但对第一个却很满意。因此,似乎不允许将
的实例传递给t
,但是使用类型本身(例如,在
谓词
)是可以的?看起来很挑剔…

不应该是这样的吗:

公共BaseGridView MyGridView{get;set;}

public BaseGridView GetMyGridView{return whatever;}
public void SetMyGridView(BaseGridView bgv){whatever=bgv;}
?


编辑。Matthew是对的,属性可能不是泛型的。您必须使用getter/setter。

以下操作可能会起作用:

public BaseGridView<T> MyGridView<T> { get; set; }
public BaseGridView MyGridView{get;set;}
原始答案的问题是类型参数必须出现在方法或类声明上,而不仅仅是返回值上

请注意,编译器无法从返回值推断泛型类型,因此您需要在每次调用
MyGridView
时指定
T

C#据我所知不支持泛型属性。您可以选择创建泛型方法或使泛型类型成为类定义的一部分

例如:

public BaseGridView<T> GetMyGridView<T>() { ... }
public void SetMyGridView<T>(T gridView) { ... }
public BaseGridView GetMyGridView(){…}
public void SetMyGridView(T gridView){…}

class-MyClass{
公共BaseGridView MyGridView{get;set;}
}

我刚试着编写了一些代码,对我来说效果很好:

    public class A<T> where T : class
    {
        public virtual A<T> ARef
        {
            get { return default(A<T>); }
        }
    }

    public class B : A<B>
    {
        public override A<B> ARef
        {
            get
            {
                return base.ARef;
            }
        }
    }
公共A类,其中T:class
{
公共虚拟ARef
{
获取{返回默认值(A);}
}
}
B级:A级
{
公共资源覆盖ARef
{
得到
{
returnbase.ARef;
}
}
}
自从你写了

但我很好奇是否有一些神秘的C#命令/语法可以帮助我实现我想要的

我想补充一点,C#4.0使得使用协方差的来替换基类型成为可能。所以你可以

公共BaseGridView MyGridView{get;set;}


因此,您得到了一个众所周知的类型,但可以返回您想要的任何BaseGridView。唯一令人遗憾的是,协方差只允许在接口上使用!:(

事实上,这是不一样的:-)您现在应该创建不是从A或B继承的C,具有未构造类型A的属性/字段,并尝试访问A的某些方法。Matthew是对的,这不起作用。的确,如果我将T添加到类定义中,它将-但随后必须为我们拥有的每个业务对象从这个通用用户控件创建构造类型。还有更好的解决方法:-)选项1:泛型方法很好,但问题是:如何声明支持字段?选项2:正确,但我需要从MyClass用户控件为我们拥有的每个业务对象创建构造类型。还有比这更好的解决方法:-)在C#4.0中,我相信您可以使用BaseGridView作为支持字段(尽管在以前的版本中您肯定不能这样做)。您的另一个选项是BaseGridView的祖先。无论如何,我认为你的问题的答案是:(1)没有符合你要求的语法,(2)你应该
public BaseGridView<T> GetMyGridView<T>() { ... }
public void SetMyGridView<T>(T gridView) { ... }
class MyClass<T> {
    public BaseGridView<T> MyGridView { get; set; }
}
    public class A<T> where T : class
    {
        public virtual A<T> ARef
        {
            get { return default(A<T>); }
        }
    }

    public class B : A<B>
    {
        public override A<B> ARef
        {
            get
            {
                return base.ARef;
            }
        }
    }