我正在使用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>'
如何更改此代码以允许使用通用列表?
答案 0 :(得分:2)
它不起作用的原因是因为 T
在编译时是未知的。您要求获取已知类型的列表并将其用作 unknown 类型的列表,这是不允许的(没有动态或其他非编译时类型安全机制) 。
由于您仍然只支持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#,我建议不要尝试使用泛型等来优化/重构。编写工作的代码(即使它使用复制粘贴,不要干,等等,然后让它更好。否则你花费很多更多的时间试图将你的程序变成一种模式,考虑程序应该如何工作。
答案 1 :(得分:1)
您可以先将其强制转换为对象,然后将其强制转换为List<T>
:
if (typeof(T) == typeof(Doctor)) { listToSearch = (List<T>)(object)doctorList; }
答案 2 :(得分:0)
你问的事是不可能的。
我建议您将listToSearch
键入IList
。这将保持您想要的通用。您可以访问所有常见的列表操作,而不必依赖于泛型。
IList listToSearch = null;
答案 3 :(得分:0)
xml
文件,这与您尝试完成的文件相差不远。我试图将暴露方法的数量从8减少到1.我最终使用的是接口而不是通用接口。
简而言之,您可以使用interface
代替generic
来获得所需的功能。 D斯坦利是对的。编写有效的代码,然后改进。这样你可以尝试删除更改以恢复功能。另外,Eric Lippert写了关于Generics的主题(帖子是堆栈溢出,我现在找不到它),如果你编写一个使用泛型的方法并立即抛出逻辑语句来理清对象是什么类型是,然后你使用泛型错误。
答案 4 :(得分:0)
如果你是,至少返回IEnumerable<T>
我可以理解使用type参数,但你在这里做的是重新发明方法重载。
试试这个:
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
}