为什么我的泛型约束仍然需要转换?

时间:2013-03-28 08:55:42

标签: c# generics

任何人都可以解释为什么在下面调用'DoTest1'方法是个问题?

至于为什么我需要将传入的GridCore对象仍然转换为泛型类型T,即使我指定T派生自GridCore,其中我的位置为T:GridCore?

由于

public partial class Form1 : Form
{
    private void button1_Click(object sender, EventArgs e)
    {
        MyTest<MyAlbum> mytest = new MyTest<MyAlbum>();
        mytest.DoTest1(new MyAlbum());
        mytest.DoTest2(new MyAlbum());
    }
}

public class GridCore { }

public class MyAlbum : GridCore
{
    public string Title { get; set; }
}

public class MyTest<T> where T : GridCore
{
    private List<T> _list = new List<T>();

    public void DoTest1(GridCore ma)
    {
        //_list.Add(ma);        <-- why doesn't this work?
        _list.Add((T)ma);
    }

    public void DoTest2(T ma)
    {
        _list.Add(ma);
    }

}

5 个答案:

答案 0 :(得分:2)

如果您希望自己的方法推断GridCoreT因为约束),那么在编译时它不能。这就是你得到错误的原因。

Generic Methods (C# Programming Guide)

  

编译器可以根据方法推断类型参数   你传递的论据;它无法仅从中推断出类型参数   约束或返回值。

答案 1 :(得分:0)

       private List<T> _list = new List<T>(); 

_list是T型,而ma

       public void DoTest1(GridCore ma)

是GridCore类型。这就是为什么它不起作用。

答案 2 :(得分:0)

C#确实要求开发人员将对象显式地转换为其任何派生类型,因为这样的转换可能会在运行时失败。 T来自GridCore。所以你可以写

GridCore gridcore = new T();

但应在

中明确转换
T t = (T)new GridCore();

答案 3 :(得分:0)

where T: GridCore表示TGridCore,即GridCoreT的基本类型或界面。

但您的列表是List<T>,也就是说,它是TT的列表,可能是GridCore的派生类。

我们假设TDerivedGridCore并且有一个字段int X,那么GridCore应该有一个字段int X

除非你明确地转换类型(或者有一个隐式运算符),否则编译器不会做出这个假设,因为转换不能保证。

为了更直观地思考,GirafeAnimal,但Animal不一定只能是Girafe; TirgetAnimal

答案 4 :(得分:0)

简而言之,因为并非所有GridCore都是T。所有T都是GridCores(因为约束),而不是相反。

想象一下:

public class MyChicken : GridCore
{
    public string FavouriteColour { get; set; }
}

....

new MyTest<MyAlbum>().DoTest1(new MyChicken());

如果您的代码被允许,那么当您期待专辑时,您现在就会有一只鸡。毋庸置疑,试图听音乐的人可能无法达到他们的期望。

您可能想要的是将DoTest1签名更改为仅接受该类处理的T

public void DoTest1(T ma)

现在,MyTest<MyAlbum>只会接受MyAlbum方法的DoTest1