【问题标题】:Converting inherited class with generic class property使用泛型类属性转换继承类
【发布时间】:2014-10-09 00:29:02
【问题描述】:

IListModel 公开了一个称为抽象类型 ListItemModel 的 Items 的通用列表属性。但是当我尝试将任何派生类转换为 IListModel 时,我得到“对象引用未设置为对象的实例”错误。

public abstract class ListItemModel
{
    public string UserName { get; set; }
    public string SomeProperty { get; set; }
}

public interface IListModel<T> where T : ListItemModel
{
    List<T> Items { get; set; }
}

public class UserListModel : IListModel<UserListItemModel>
{
    public string Query { get; set; }
    public int TotalUsers { get; set; }

    public List<UserListItemModel> Items { get; set; }
}

public class UserListItemModel : ListItemModel
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

var users = new UserListModel
{
    Query = "a",
    TotalUsers = 1111,
    Items = new List<UserListItemModel>
    {
        new UserListItemModel {FirstName = "a", LastName = "b"}
    }
};

// later in the application users will be passed around as an object which 
// must cast it to  IListModel<ListItemModel> in order to access its properties
// but converted will return null
var converted = users as IListModel<ListItemModel>;


foreach (var item in converted .Items)
{
    item.SomeProperty = DoSomethingHere(item.UserName);
}

我在这里想要实现的是能够从 ListItemModel 基类填充 SomePropery。

【问题讨论】:

    标签: c# generics


    【解决方案1】:

    请参考:as (C# reference)

    但是,如果无法进行转换,则 as 返回 null 而不是引发异常。

    基本上,发生的情况是您正在执行无效转换,而该无效转换的结果取决于所使用的转换形式。

    var converted = users as IListModel<ListItemModel>; // converted is null
    var converted = (IListModel<ListItemModel>)users;   // raises exception
    

    强制转换真的有必要吗? UserListModel : IListModel&lt;UserListItemModel&gt; 似乎表明它是您想要的类型的 IListModel,所以您应该能够将它提供到 foreach 块中并从中工作,不是吗?

    【讨论】:

    • 正如我稍后在代码中作为注释添加的那样,用户对象将在代码中作为对象传递,该对象必须将其转换为 IListModel 才能访问其属性。 UserListModel 也是 IListModel 的众多实现之一。
    【解决方案2】:

    创建通用列表项引用接口:

    public interface IListItemModel
    {
        List<ListItemModel> Items { get; }
    }
    

    让您的类使用显式构造函数实现:

    List<LIstItemModel> IListModel.Items
    {
      get { return this.Items; }
    }
    

    然后您可以将用户强制转换为 IListModel。

    【讨论】:

    • 感谢您的回复,但我会将用户作为必须转换为 IListModel 才能访问其属性的对象。
    • 假设您将用户作为对象类型,首先您必须将其转换为它的基本类型,即 IListModel,然后您可以访问 Items 属性。问题是投射失败。
    • 这行得通!唯一的事情是我必须将显式构造函数添加到所有派生类。我希望有一个更清洁的解决方案。但这暂时解决了我的问题。非常感谢。
    • 显式构造函数做什么?它应该只返回现有的 Items 属性集合
    • 在您的回答的帮助下,我可以想出一个解决方案。我也发布了代码。非常感谢。
    【解决方案3】:

    感谢“Brian Mains”和“Kyle Baran”,我的问题得到了解决。这是工作代码:

    public abstract class ListItemModel
    {
        public string UserName { get; set; }
    }
    
    public interface IListModel
    {
        List<ListItemModel> ListItems { get; }
    }
    
    public abstract class BaseListModel<T> : IListModel where T : ListItemModel
    {
        public List<T> Items { get; set; }
    
        public List<ListItemModel> ListItems
        {
            get { return Items.Cast<ListItemModel>().ToList(); }
        }
    }
    
    public class UserListModel : BaseListModel<UserListItemModel>
    {
        public string Query { get; set; }
        public int TotalUsers { get; set; }
    }
    
    public class UserListItemModel : ListItemModel
    {
        public string FirstName { get; set; }
        public string LastName { get; set; }
    }
    
    var users = new UserListModel
    {
        Query = "a",
        TotalUsers = 1111,
        Items = new List<UserListItemModel>
        {
            new UserListItemModel {FirstName = "a", LastName = "b"}
        }
    };
    
    // and finally I can cast the collection to IListModel
    var converted = users as IListModel;
    
    
    foreach (var item in converted .Items)
    {
        item.SomeProperty = DoSomethingHere(item.UserName);
    }
    

    【讨论】:

      猜你喜欢
      • 2015-11-18
      • 1970-01-01
      • 2012-11-29
      • 2019-03-08
      • 1970-01-01
      • 2018-09-27
      • 2015-09-15
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多