如何将泛型列表设置为相同类型的预先存在列表
本文关键字:列表 同类型 存在 泛型 设置 | 更新日期: 2023-09-27 17:52:56
我使用c#并有4个现有列表,每个列表都是不同的类型(即List<Doctor>
, List<Patient>
等)
我有一个通用的搜索方法,它接收类型T,应该使用LINQ搜索基于类型T的适当列表。
我创建了一个var List<T> listToSearch
,并希望使用if将其设置为适当的列表,但我不能将listToSearch
设置为其中的任何一个。
// at class level:
private List<Doctor> doctorList;
private List<Patient> patientList;
private List<Visit> visitList;
private List<Treatment> treatmentList;
public IEnumerable search<T>(string field, string rangeStart, string rangeEnd = null)
{
List<T> listToSearch = null;
if (typeof(T) == typeof(Doctor)) { listToSearch = doctorList; }
if (typeof(T) == typeof(Patient)) { listToSearch = patientList; }
if (typeof(T) == typeof(Visit)) { listToSearch = visitList; }
if (typeof(T) == typeof(Treatment)) { listToSearch = treatmentList; }
// more code that isn't relevant to the question here
}
每个typeof(T)
行显示一个错误:
"不能隐式地将类型
'System.Collections.Generic.List<Doctor/Patient/Visit/Treatment>'
转换为'System.Collections.Generic.List<T>'
如何修改这段代码以允许使用泛型列表?
不起作用的原因是 T
在编译时是未知的。您要求使用已知类型的列表并将其用作未知类型的列表,这是不允许的(没有动态或其他非编译时类型安全机制)。
因为你只支持4种类型,听起来你需要4个search
方法来调用一个通用的公共方法(如果合适的话):
public IEnumerable<Doctor> searchDoctors(string field, string rangeStart, string rangeEnd = null)
{
List<Doctor> listToSearch = doctorList;
// more code that isn't relevant to the question here
}
public IEnumerable<Patient> searchPatients(string field, string rangeStart, string rangeEnd = null)
{
List<Patient> listToSearch = patientList;
// more code that isn't relevant to the question here
}
public IEnumerable<Visit> searchVisits(string field, string rangeStart, string rangeEnd = null)
{
List<Visit> listToSearch = visitList;
// more code that isn't relevant to the question here
}
public IEnumerable<Treatment> searchTreatments(string field, string rangeStart, string rangeEnd = null)
{
List<Treatment> listToSearch = treatmentList;
// more code that isn't relevant to the question here
}
否则,你将有大量的代码来验证/转换类型,这很容易受到运行时错误的影响。
注:
因为你是c#新手-我建议不要尝试使用泛型等进行过多的优化/重构。编写工作的代码(即使它使用复制粘贴,而不是DRY等),然后使更好。否则,您将花费大量时间试图将程序硬塞进某种模式,而不是考虑程序应该如何工作。
您可以先将其强制转换为一个List<T>
对象:
if (typeof(T) == typeof(Doctor)) { listToSearch = (List<T>)(object)doctorList; }
你要求的事情是不可能的。
我建议将您的listToSearch
输入为IList
。这将保持尽可能多的通用性。您可以访问所有常见的列表操作,而不必依赖泛型。
IList listToSearch = null;
在了解泛型的用途之前,我遇到了类似的情况。在我的情况下,我试图减少将数据添加到处理程序所需的方法数量,然后将其写入xml
文件,这与您想要完成的目标并不太远。我试图将暴露的方法数量从8个减少到1个。我最终使用了一个接口,而不是一个泛型。
简而言之,您可能可以通过使用interface
而不是generic
来获得所需的功能。斯坦利是对的。编写有效的代码,然后改进。这样,您就可以尝试消除更改以恢复功能的选项。此外,Eric Lippert写了关于泛型的主题(这个帖子是stack overflow,我现在找不到它),如果你写了一个使用泛型的方法,并立即抛出逻辑语句来分类对象类型是什么,那么你使用泛型是错误的。
如果你是,至少,返回IEnumerable<T>
我可以理解使用类型参数,但你在这里做的是重新发明方法重载。
试试这个:
public IEnumerable<Doctor> SearchDoctors(string field, string rangeStart, string rangeEnd = null)
{
return Search(doctorList, field, rangeStart, rangeEnd);
}
public IEnumerable<Patient> SearchPatients(string field, string rangeStart, string rangeEnd = null)
{
return Search(patientList, field, rangeStart, rangeEnd);
}
public IEnumerable<Visit> SearchVisits(string field, string rangeStart, string rangeEnd = null)
{
return Search(visitList, field, rangeStart, rangeEnd);
}
public IEnumerable<Treatment> SearchTreatments(string field, string rangeStart, string rangeEnd = null)
{
return Search(treatmentList, field, rangeStart, rangeEnd);
}
private IEnumerable<T> Search<T>(IEnumerable<T> list, string field, string rangeStart, string rangeEnd)
{
// more code that isn't relevant to the question here
}
顺便说一下,您是否知道编译后调用者中的默认参数值是硬编码的?
考虑改成:
public IEnumerable<Doctor> SearchDoctors(string field, string rangeStart)
{
return Search(doctorList, field, rangeStart);
}
public IEnumerable<Doctor> SearchDoctors(string field, string rangeStart, string rangeEnd)
{
return Search(doctorList, field, rangeStart, rangeEnd);
}
public IEnumerable<Patient> SearchPatients(string field, string rangeStart)
{
return Search(patientList, field, rangeStart);
}
public IEnumerable<Patient> SearchPatients(string field, string rangeStart, string rangeEnd)
{
return Search(patientList, field, rangeStart, rangeEnd);
}
public IEnumerable<Visit> SearchVisits(string field, string rangeStart)
{
return Search(visitList, field, rangeStart);
}
public IEnumerable<Visit> SearchVisits(string field, string rangeStart, string rangeEnd)
{
return Search(visitList, field, rangeStart, rangeEnd);
}
public IEnumerable<Treatment> SearchTreatments(string field, string rangeStart)
{
return Search(treatmentList, field, rangeStart);
}
public IEnumerable<Treatment> SearchTreatments(string field, string rangeStart, string rangeEnd)
{
return Search(treatmentList, field, rangeStart, rangeEnd);
}
private IEnumerable<T> Search<T>(IEnumerable<T> list, string field, string rangeStart, string rangeEnd = null)
{
// more code that isn't relevant to the question here
}