简体   繁体   English

如何将通用列表设置为相同类型的现有列表?

[英]how to set generic list to a pre-existing list of the same type?

I am using c# and have 4 existing lists, each of a different type (ie List<Doctor> , List<Patient> etc') 我正在使用c#并有4个现有列表,每个列表的类型不同(即List<Doctor>List<Patient>等)

I have a generic search method which receives type T and should search using LINQ the appropriate list based on the type T. 我有一个通用的搜索方法,该方法接收类型T,并且应该使用LINQ基于类型T来搜索适当的列表。

I created a var List<T> listToSearch and wanted to set it to the appropriate list using if's, but I can't set listToSearch to any of them. 我创建了一个var List<T> listToSearch并希望使用if将其设置为适当的列表,但是我无法将listToSearch设置为其中的任何一个。

Code: 码:

// 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
    }

Each typeof(T) line brings up an error: 每行typeof(T)引发一个错误:

"Cannot implicitly convert type 'System.Collections.Generic.List<Doctor/Patient/Visit/Treatment>' to 'System.Collections.Generic.List<T>' “无法将类型'System.Collections.Generic.List<Doctor/Patient/Visit/Treatment>'隐式转换为'System.Collections.Generic.List<T>'

How do I change this code to allow for the use of Generic lists? 如何更改此代码以允许使用通用列表?

The reason it doesn't work is because T is not known at compile time . 它不起作用的原因是因为T在编译时未知 You are asking to take a list of a known type and use it as a list of an unknown type, which is not allowed (without dynamics or some other non-compile-time-type-safe mechanism). 您要获取一个已知类型的列表,并将其用作未知类型的列表,这是不允许的(没有动态性或其他一些非编译时类型安全机制)。

Since you're only supporting 4 types anyways, it sounds like you need four search methods that call a generic common method (if appropriate): 由于无论如何您仅支持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
}

otherwise you're going to have a lot of code validating/casting/converting types that is susceptible to runtime errors. 否则,您将有很多容易受到运行时错误影响的代码验证/广播/转换类型。

Side note: 边注:

Since you are new to C# - I would recommend not trying to optimize/refactor too much using generics, etc. Write code that works (even if it's using copy-paste, not DRY, etc.), then make it better . 既然你是新来的C# -我会建议不要试图优化/重构过多使用泛型等编写代码工作 (即使它使用复制粘贴,不干燥等),然后使它更好 Otherwise you spend a lot more time trying to shoehorn your program into some pattern that thinking about how the program should work. 否则,你花了很多时间试图硬塞进你的程序到一些模式的思考程序应该如何工作。

您可以先将其转换为对象,然后将其转换为List<T>

if (typeof(T) == typeof(Doctor)) { listToSearch = (List<T>)(object)doctorList; }

The thing you are asking is not possible. 您要问的事情是不可能的。

I would recommend to type your listToSearch as IList . 我建议将您的listToSearch键入为IList This will keep as much generic as you want. 这将保持所需的通用性。 You can access all common list actions and you don't have to rely on generics. 您可以访问所有常见的列表操作,而不必依赖泛型。

IList listToSearch = null;

I ran into something like this before I understood what generics are for. 在了解泛型用途之前,我遇到了这样的问题。 In my case I was trying to reduce the number of methods that were needed to add data to a handler before writing it as an xml file which isn't too far from what you are trying to accomplish. 以我为例,我试图减少将数据添加到处理程序之前需要的方法数量,然后将其写入xml文件,这与您要完成的目标相差不远。 I was trying to reduce the number of exposed methods from 8 to 1. I ended up using an interface instead of a generic. 我试图将公开方法的数量从8个减少到1个。我最终使用了接口而不是通用接口。

In short, you probably can get your desired functionality by using an interface instead of a generic . 简而言之,您可以通过使用interface而不是generic来获得所需的功能。 D Stanley is correct. D史丹利是正确的。 Write code that works, then improve. 编写有效的代码,然后加以改进。 That way you can try something with the option of eliminating the changes to restore the functionality. 这样,您可以尝试一些消除删除更改以恢复功能的选项。 Also, Eric Lippert wrote on the subject on Generics (the post is in stack overflow, I just can't find it right now) that if you write a method for using a generic and immediately throw in logic statements to sort out what the object type is, then you are using generics wrong. 另外,埃里克·利珀特(Eric Lippert)在泛型上写了这个主题(该帖子在堆栈溢出中,我现在找不到),如果您编写了一个使用泛型的方法并立即抛出逻辑语句来整理对象的内容类型是,那么您使用的是泛型错误。

If you were, at least, returning IEnumerable<T> I could understand using the type parameter, but what you are doing here is reinventing method overloading. 如果至少返回了IEnumerable<T>我可以使用type参数理解,但是您在这里所做的是重新创建方法重载。

Try this: 尝试这个:

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
}

By the way, are you aware that default argument values are hardcode in the caller after compilation? 顺便说一句,您是否知道默认参数值在编译后在调用方中是硬编码的?

Consider changing to this: 考虑更改为:

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
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM