![](/img/trans.png)
[英]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.