2017-09-14 46 views
-1

如果标题的措辞不正确,请原谅我。如何在工厂返回T时访问值列表<T>以及未知

我从各种设备的数据库表中检索数据并构建一个列表。不同的设备可能具有相同的属性,并且肯定会有一些不同的属性,所以我使用工厂模式在运行时创建需要的任何一个。

工厂类:

public interface IImportModel 
{ 
    IList CreateImportList(SqlDataReader reader); 
} 

和混凝土类:

public class Device1ImportModel : IImportModel 
{ 
    public string SerialNumber { get; set; } 
    public string PartA { get; set; } 

    public IList CreateImportList(SqlDataReader reader) 
    { 
     Device1ImportModel linkedItem = new Device1ImportModel(); 

     List<Device1ImportModel> importList = new List<Device1ImportModel>(); 

     while (reader.Read()) 
     { 
      linkedItem = new Device1ImportModel(); 

      linkedItem.SerialNumber = reader["SerialNo"].ToString(); 
      linkedItem.PartA = reader["PartA"].ToString(); 

      importList.Add(linkedItem); 
     } 

     return importList; 
    } 
} 

我从工厂创建设备:

importModel = ImportModelFactory.CreateImportModel("Device1"); 

现在,当我想遍历importModel,我在尝试访问item.SerialNumber的行上收到编译时错误。

foreach (var item in importList)     
{ 
     string number = item.SerialNumber; 
} 

错误:

'object' does not contain a definition for 'SerialNumber' and no extension method 'SerialNumber' accepting a first argument of type 'object' could be found.

如果我把一个断点和项目变量悬停,我能看到的属性和价值。

我尝试使用动态而不是var,但后来在我的代码中,我不能再使用Linq或Lambda查询。

  1. 如何访问这些值?
  2. 我可以使用反射将IList转换为List吗?

编辑1

添加的代码为CreateImportModel:

static public IImportModel CreateImportModel(DeviceType device) 
{ 
    switch (device) 
    { 
     case DeviceType.Device1: 
      return new Device1ImportModel(); 

     case DeviceType.Device2: 
      return new DeviceImportModel(); 

     default: 
      return null; 
    } 
} 
+0

请包含'CreateImportModel'的源代码。 – mjwills

+0

所有设备类型是否都有'SerialNumber'? – mjwills

回答

2

变化IListList<Device1ImportModel>(或IList<Device1ImportModel>IReadOnlyList<Device1ImportModel>)。

public List<Device1ImportModel> CreateImportList(SqlDataReader reader) 

IList是一个较旧的接口(预仿制药),因此,如果您使用IList(而不是IList<Device1ImportModel),则编译器/运行时没有数据的Type的概念(即它把它作为object),即:

'object' does not contain a definition for 'SerialNumber' and no extension method 'SerialNumber' accepting a first argument of type 'object' could be found.

您可能还需要改变接口:

public interface IImportModel<T> 
{ 
    List<T> CreateImportList(SqlDataReader reader); 
} 

和类:

public class Device1ImportModel : IImportModel<Device1ImportModel> 
{ 
    public string SerialNumber { get; set; } 
    public string PartA { get; set; } 

    public List<Device1ImportModel> CreateImportList(SqlDataReader reader) 
    { 

你可能也想更改CreateImportModel所以不要这么说:

ImportModelFactory.CreateImportModel("Device1"); 

你,而不是把它想:

ImportModelFactory.CreateImportModel<Device1ImportModel>(); 

使混凝土Device1ImportModel返回(因而SerialNumber是访问)。

+0

这不起作用,因为我的接口设置为IList CreateImportList(SqlDataReader reader);我有超过一个具体的类,并不会提前知道哪一个被称为... – Neill

+1

@Neill然后遍历该列表,并期望它具有仅在一个具体类型中找到的属性是设计缺陷。如果所有具体类型都有一个'SerialNumber',那么将它作为接口的一部分并使用'List '。 – Rotem

+0

更新是否有助于@Neill? – mjwills

3

如果你不能改变你的方法的签名,你可以使用:

foreach (var item in importList.Cast<Device1ImportModel>())     
{ 
    string number = item.SerialNumber; 
} 

这将抛出一个异常,但是,如果会出现importList的集合,是不是Device1ImportModel或其派生类对象中的。

如果你不知道的是,在列表中的所有对象都是这种类型的,并希望避免异常,使用此apporach:

foreach (var item in importList.OfType<Device1ImportModel>())     
{ 
    string number = item.SerialNumber; 
} 
+0

我不知道哪个班级要打电话。 – Neill

+1

@Neill,如果你不知道哪个类会期望,你怎么能确定会有'SerialNumber'属性?那么你的问题没有解决方案。 – dymanoid

+0

有一些属性,所有类将始终有。 SerialNumber就是其中之一。 – Neill

0

最后我只使用一个单独的类来保存所有属性,每个其他的具体课程是否使用它们。

它不理想,但工程。

我宁愿依靠每个具体类来负责它自己的属性。

相关问题