[英]How to add item to generic list through ModelItem.Properties class?
[英]How to add an item to a generic list?
让我解释一下我要完成的工作。 我大约有十二种不同的对象列表和十二种不同的方法,以根据它们包含的内容填充它们。 我一直在尝试对代码进行重构,以消除“湿”部分,并将其降至不可减少的最小值。
十二个类别中的每个类别都非常相似。 这样想他们。 有些具有更多的属性,有些具有较少的属性,并且具有各种类型。
class car
{
public string brand_model { get; set; }
public int numberOfDoors { get; set; }
public string engineType { get; set; }
}
class bike
{
public string brand_model { get; set;}
public int numberOfMainCogs { get; set;}
public int weight { get; set;}
}
我有三种方法。 顶部方法传递给下一个方法,无论该方法当前正在使用哪个列表作为泛型:
List<car> carList = new List<car>();
List<bike> bikeList = new List<bike>();
switch (vehicleType)
{
case ("car"):
Populate(ref carList);
break;
case ("bike"):
Populate(ref bikeList);
break;
}
我称之为填充,它只是将那个空列表发送到从数据库读取的方法。
public bool Populate<T>(ref List<T> vehicleList)
{
//figure out what kind of list was passed in
//do some stuff to connect to database
//call appropriate method to add items to that list
switch(vehicleType)
{
case("car"):
readCarInformation(reader, ref vehicleList);
break;
case("bike"):
readBikeInformation(reader, ref vehicleList);
break;
}
假设这是一辆汽车。 这是我的方法声明。
private void readCarInformation(AseDataReader reader, ref List<car> carList)
{
while (reader.Read())
{
carList.Add(new car
{
brand_model = SafeGetInt(reader, 0),
numberOfDoors = SafeGetInt(reader, 1),
engineType = SafeGetString(reader, 2)
});
}
}
}
我现在已经尝试了多种方法来使其工作。 我正在尝试填充我在原始方法中创建的carList。 我做错了什么?
是的,我仍然是新手。
通常,当您必须使用反射来确定泛型参数的“类型”,然后根据该类型执行其他操作时,则不应使用泛型。 更好的方法是改为对每种类型重载(分解不依赖于反射的任何通用代码):
public bool Populate(ref List<car> carList)
{
//do some stuff to connect to database
AseDataReader reader = GetReader();
readCarInformation(reader, ref carList);
}
public bool Populate(ref List<bike> bikeList)
{
//do some stuff to connect to database
AseDataReader reader = GetReader();
readBikeInformation(reader, ref bikeList);
}
代码量大致相同(交换了多种方法的switch
开销),并且编译时安全,并且提高了可测试性(您可以分别测试每个Populate
方法,而不是对多个案例测试一个Populate
方法)。
我还会质疑是否需要ref
。 如果您只是添加到传入的列表实例中,则ref
是不必要的。 如果您要分配一个新列表,则out
可能更合适(或使用List
返回类型而不是布尔值)。
ref
,因为当作为参数传递时不会复制对象。 readXXInformation
应该只读取信息,将信息放在过于专业的列表中,应该在其他地方执行。 认为您可能希望将其用于其他目的。 这里是一种方法:
List<car> carList = new List<car>();
List<bike> bikeList = new List<bike>();
switch (vehicleType)
{
case ("car"):
carList.AddRange(readCarInformation(reader));
break;
case ("bike"):
bikeList.AddRange(readBikeInformation(reader));
break;
}
您的读者将如下所示:
private IEnumerable<Car> readCarInformation(AseDataReader reader)
{
while (reader.Read())
{
yield return new car
{
brand_model = SafeGetInt(reader, 0),
numberOfDoors = SafeGetInt(reader, 1),
engineType = SafeGetString(reader, 2)
};
}
}
所以是的,我删除了您的Populate
函数。 如果您确实需要做更多的事情,只是将元素添加到列表中,则可以使用如下函数:
private void Populate<T>(IList<T> destination, IEnumerable<T> source)
{
destination.AddRange(source);
... // others stuffs.
}
您的切换将是:
switch (vehicleType)
{
case ("car"):
Populate(carList, readCarInformation(reader));
break;
case ("bike"):
Populate(bikeList, readBikeInformation(reader));
break;
}
[编辑]
您也可以像这样分解readXXInformation
:
private IEnumerable<T> readObjectInformation<T>(AseDataReader reader, Func<AseDataReader, T> objectBuilder)
{
while (reader.Read())
{
yield return objectBuilder(reader);
}
}
并使用像这样的小型对象生成器:
private Car carBuilder(AseDataReader reader)
{
return new car
{
brand_model = SafeGetInt(reader, 0),
numberOfDoors = SafeGetInt(reader, 1),
engineType = SafeGetString(reader, 2)
};
}
最后,您可以像这样使用它:
switch (vehicleType)
{
case ("car"):
carList.AddRange(readObjectInformation(reader, carBuilder));
break;
case ("bike"):
bikeList.AddRange(readObjectInformation(reader, bikeBuilder));
break;
}
要么
private void Populate<T>(AseDataReader reader, IList<T> destination, Func<AseDataReader, T> objectBuilder)
{
destination.AddRange(readObjectInformation(reader, objectBuilder));
... // others stuffs.
}
...
switch (vehicleType)
{
case ("car"):
Populate(reader, carList, carBuilder);
break;
case ("bike"):
Populate(reader, bikeList, bikeBuilder);
break;
}
有很多解决方案。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.