非构造泛型作为属性(例如List <t>)</t>

时间:2010-06-18 15:27:49

标签: c# generics interface properties

问题

这是我偶然发现的事情,能够以某种方式解决它。但是现在它回来了,依赖于我的好奇心 - 我很想得到明确的答案。

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

现在有必要创建一个引用这些构造类型的用户控件来控制BaseGridView中的一些 共享 功能(例如过滤)。因此,我希望在用户控件上创建一个公共属性,使我能够将它附加到Designer /代码中的任何BaseGridViewpublic BaseGridView<T> MyGridView { get; set; }。问题是,它不起作用:-)编译时,我收到以下消息:

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

解决方案?

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

但我很好奇是否存在一些神秘的C#命令/语法可以帮助我达到我想要的效果 - 而不用我真正不需要的界面来污染我的解决方案: - )

编辑:作为参考,我确实尝试了这种无辜的解决方法:BaseGridView<object> MyGridView { get; set; },并且......它仍然不是答案:无法隐式转换类型'InvoiceGridView'到'BaseGridView&lt; object&gt;'

部分成功(编辑2)

好的,因为协方差只在接口上支持,我承认失败并定义了一个接口(只显示了一些):

public interface IBaseGridView<out T> where T : class
{
    bool ScrollTo(Predicate<T> criteria);
    bool ScrollTo(T object);
}

我现在能够将我心爱的InvoiceGridView投射到一个IBaseGridView<object> - 这很棒,我又是一个快乐的男孩:-)然而,第二个{ {1}}在编译时给我带来麻烦:

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

我现在必须将签名修改为ScrollTo - 这不是理想的,但可以完成工作。令我感到惊讶的是,编译器抱怨第二个ScrollTo(object o),但对第一个感到满意。所以似乎不允许传递ScrollTo实例,但是使用类型本身(例如在out T中)可以吗?看起来相当挑剔...

5 个答案:

答案 0 :(得分:1)

根据我的知识,C#不支持通用属性。您可以选择创建泛型方法,也可以将泛型类型作为类定义的一部分。

例如:

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

class MyClass<T> {
    public BaseGridView<T> MyGridView { get; set; }
}

答案 1 :(得分:1)

自从你写了

  

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

我想补充一点,C#4.0可以使用&lt;替换基类型的派生类型。出T&gt;为了协方差。所以你可以做到

public BaseGridView&lt; Object &gt; MyGridView {get;组; }

所以你得到一个众所周知的类型,但你可以返回你想要的任何BaseGridView。不幸的是,唯一的问题是协方差只允许在接口上使用! :(

答案 2 :(得分:0)

不应该是这样的:

public BaseGridView MyGridView {get;组; }

public BaseGridView<T> GetMyGridView<T> { return whatever; }
public void SetMyGridView<T>( BaseGridView<T> bgv) { whatever = bgv; }

...

编辑。马修是对的,属性可能不是通用的。你必须使用getter / setter。

答案 3 :(得分:0)

以下可能有效:

public BaseGridView<T> MyGridView<T> { get; set; }

原始答案的问题是类型参数必须出现在方法或类声明中,而不仅仅出现在返回值上。

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

答案 4 :(得分:0)

我只是尝试了一些代码,它对我来说很好用:

    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;
            }
        }
    }