【问题标题】:C# Collection with class inheritance and generic type inheritance does not allow to add inherited class具有类继承和泛型类型继承的 C# 集合不允许添加继承的类
【发布时间】:2020-09-08 06:00:02
【问题描述】:

我遇到了一些可能的事情,但不起作用。

这里是示例类,

abstract class BaseModel { }

abstract class BaseViewModel<T> where T : BaseModel
{
    protected T model;
}

class ModelA : BaseModel { }

class ViewModelA : BaseViewModel<ModelA> { }

现在我试着去做

class Program
{
    static void Main(string[] args)
    {
        var collection = new List<BaseViewModel<BaseModel>>();
        collection.Add(new ViewModelA());
    }
}

直觉上,它看起来是有效的。但是无法添加ViewModelA

我想知道为什么这是不可能的,并解决这种情况。

【问题讨论】:

  • A BaseViewModel&lt;BaseModel&gt; 必须能够处理继承自 BaseModel 的任何内容。你传递给它一个ViewModelA,它只能处理从BaseModel 继承的东西的子集,即从ModelA 继承的对象。所以不允许赋值。
  • @JohnWu 那么有什么解决办法吗?
  • 解决方法是:重新考虑您的设计。您的列表真的是基本类型还是所有实体都是派生类型?您使用该集合的 cinsuming 代码是什么?
  • 想象一下这成为可能。然后你的代码的用户也可以写collection.Add(AnotherViewModel)
  • @HimBromBeere 我试图允许collection.Add(AnotherViewModel) 具有继承BaseViewModel&lt;T&gt; where T : BaseModel 的限制。我知道这可能是一个设计问题,但我很好奇为什么它不起作用。

标签: c# generics inheritance


【解决方案1】:

ViewModelA 不等于 BaseViewModel&lt;BaseModel&gt;,尽管您可能认为它是

这是因为类是不变的。

  • 不变性:表示只能使用原来指定的类型

  • 协方差:使您能够使用比最初指定的更多派生类型

实现您想要的(可能)的一种方法是通过out generic modifier 使用协变接口参数。但是,它有一定的局限性。 类型参数只能作为接口方法返回类型,不能作为方法参数的类型

示例

public interface IBaseViewModel<out T>  where T : BaseModel 
{ 
   ... 
}

abstract class BaseViewModel<T> : IBaseViewModel<T> where T : BaseModel 
{
   protected T model; 
}

class ModelA : BaseModel { }

class ViewModelA : BaseViewModel<ModelA> { }

static void Main(string[] args)
{
   var collection = new List<IBaseViewModel<BaseModel>>();
   collection.Add(new ViewModelA()); // this now works
}

【讨论】:

    【解决方案2】:

    我对您的实现有不同的理论,根据您的实现,您的BaseViewModel&lt;T&gt;BaseModel 都是抽象的,这意味着您不能实例化抽象类,这意味着您不能使用BaseViewModel&lt;BaseModel&gt; baseModel = new ViewModelA();。当您添加到集合时,您试图为违反抽象类规则的抽象类创建一个实例。我已经对您进行了一些修改,以便您可以添加到集合中。

    
    abstract class BaseModel { }
    
    abstract class BaseViewModel<T> where T : BaseModel
    {
         protected T model;
    }
    
    class ModelA : BaseModel { }
    
    class ViewModelA : BaseViewModel<ModelA> { }
    
    static async Task Main(string[] args)
    {
        var collection = new List<BaseViewModel<ModelA>>();
        collection.Add(new ViewModelA());
    }
    

    您也可以按照前面的答案制作界面来制作解耦类。

    【讨论】:

    • 感谢您帮助我更好地了解这种情况,但是如果收藏到List&lt;BaseViewModel&lt;ModelA&gt;&gt;,我无法将ViewModelB : BaseViewModel&lt;ModelB&gt; 添加到收藏中。
    • 显然你不能 ViewModelB: BaseViewModel&lt;ModelB&gt; 到集合中,因为泛型类型绑定到 ModelA 的实例为 BaseViewModel&lt;ModelA&gt;。您可以做的是创建一个在ModelAModelB 以及List&lt;BaseViewModel&lt;YourInterface&gt;&gt; 中都继承的接口。然后您可以添加任何继承接口的对象,请参阅@Michael Randall 发布的上一个答案
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-09-27
    • 2015-09-15
    • 2018-08-01
    相关资源
    最近更新 更多