【问题标题】:Type cannot be used as type parameter 'T' in the generic type or method - Why? [duplicate]类型不能用作泛型类型或方法中的类型参数“T” - 为什么? [复制]
【发布时间】:2014-07-02 11:17:27
【问题描述】:

我正在尝试从一个接口继承两个不同的模型。这些模型应该作为列表或集合传递给方法。现在我收到此错误消息:

The type 'InheritanceTest.FooModel' cannot be used as type parameter 'T' in the generic type or method 'InheritanceTest.Service.DoSomethingWith<T>(System.Collections.Generic.IEnumerable<T>)'. There is no implicit reference conversion from 'InheritanceTest.FooModel' to 'InheritanceTest.IModel<InheritanceTest.IModelItem>'. C:\Work\InheritanceTest\InheritanceTest\Program.cs 14 13 InheritanceTest

有人可以解释一下,我做错了什么吗? :D

演示代码:

interface IModel<T> where T : IModelItem
{
    string Name { get; set; }

    IEnumerable<T> Items { get; set; }
}

interface IModelItem
{
    string Name { get; set; }
}

class FooModel : IModel<FooModelItem>
{
    public FooModel()
    {
        Items = new List<FooModelItem>();
    }

    public string Name { get; set; }
    public IEnumerable<FooModelItem> Items { get; set; }
}

class FooModelItem : IModelItem
{
    public string Name { get; set; }
}

class Program
{
    static void Main(string[] args)
    {
        var fooLists = new List<FooModel>();
        var barLists = new ObservableCollection<BarModel>();

        var service = new Service();

        service.DoSomethingWith(fooLists);
        service.DoSomethingWith(barLists);
    }
}

class Service
{
    public void DoSomethingWith<T>(IEnumerable<T> list) where T : IModel<IModelItem>
    {
        foreach (var model in list)
        {
            Debug.WriteLine(model.Name);

            foreach (var item in model.Items)
            {
                Debug.WriteLine(item.Name);
            }
        }
    }
}

演示项目可以在 GitHub 上找到: https://github.com/SunboX/InheritanceTest/blob/master/InheritanceTest/Program.cs

【问题讨论】:

  • 那么FooModelItemIModelItem是什么关系?我相信class FooModel : IModel&lt;IModelItem&gt; 可以实现您想要实现的目标
  • 更新了代码以包含 IModelItemFooModelItem
  • Nikhil Agrawal 可能错误地认为这个问题与您之前的问题完全相同。在这里,您遇到了协方差/逆变难题。最好查看有关它们的其他问题,例如 this one

标签: c# inheritance interface


【解决方案1】:

举例说明为什么你不能这样做,想象一下除了FooModelFooModelItem,你还有BarModelItem。现在假设你这样做:

IModel<FooModelItem> fooModel = new FooModel();
IModel<IModelItem> iModel = fooModel;
iModel.Items = new List<BarModelItem>(new BarModelItem());

FooModelItem fooModelItem = fooModel.Items.First();

如果这是有效的代码,您就会遇到麻烦,因为您在最后一行返回的项目实际上不是FooModelItem,而是BarModelItem

如果你仔细阅读每一行,你会发现唯一可能的错误行是第二行。这说明了为什么IModel&lt;FooModelItem&gt; 不能分配给IModel&lt;IModelItem&gt;,即使FooModelItem : IModelItem 也是如此。无法完成该任务正是您的方法调用失败的原因。

您可以研究通用协变和逆变,以了解在某些情况下如何避免这种情况,但如果不修改模型,它在您的特定情况下无济于事。

【讨论】:

猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多