0

I am trying to join two different list together using the Concat Method as shown below. I need the second list to be added to the first list, so that it can come as one lIst.

var term = dc.AgentTerm(Agentcode).ToList();
var hosp = dc.AgentHospCashPlan(Agentcode).ToList();
var life = term.Concat(hosp).ToList();

But when i tried it, I get this error.

Error 16 Instance argument: cannot convert from System.Collections.Generic.List<IbsMobile.AgentTerm_Result> to System.Linq.IQueryable<IbsMobile.AgentHospCashPlan_Result> C:\Project\IbsMobile\IbsMobile\Controllers\ParamController.cs 506 24 IbsMobile

Error 17 System.Collections.Generic.List<IbsMobile.AgentTerm_Result> does not contain a definition for 'Concat' and the best extension method overload System.Linq.Queryable.Concat<TSource>(System.Linq.IQueryable<TSource>, System.Collections.Generic.IEnumerable<TSource>) has some invalid arguments C:\Project\IbsMobile\IbsMobile\Controllers\ParamController.cs 506 24 IbsMobile

I checked online and all I see is how to convert 'System.Linq.IQueryable' to 'System.Collections.Generic.IList'.

The results that I'm assigning to term and Hosp are from stored procedures.

I have used the concat method before on lists with the same class and it worked fine.

I am guessing this error is because the results sets are from different classes.

I know this is a novice question but I'm not sure exactly what I'm doing wrong.

  • _I am guessing this error is because the results sets are from different classes_ - if `term` and `host` are lists of different types - then it is not possible. – Fabio Mar 04 '19 at 10:24
  • Naive question, what are the types of list `term` and the type of list `hosp` ? – Christos Mar 04 '19 at 10:24
  • @Fabio , Yes, They are of different classes, since they are stored procedures, they are getting different results sets from the DB. I want to add the two lists together, is not possible to join them. – Clinton Okorie Mar 04 '19 at 10:27
  • Does it really make sense to put the two lists into one? – Gilad Green Mar 04 '19 at 10:32
  • Looks like XY problem. Why you want concatenate collections of different types? How you gonna use them. Consider create a class which contains two properties of collections you need. – Fabio Mar 04 '19 at 10:49
  • Try something like this using object[] : term.Select(x => new object[] { x.prop1, x.prop2, x.prop3}).Concat(hosp); – jdweng Mar 04 '19 at 10:51
  • @ClintonOkorie - I would love to hear the answer to Fabio's question. – Enigmativity Mar 20 '19 at 12:11
  • @Enigmativity Oh Okay, Which of the Questions. If it was why I was concatenating different types, I had a couple of stored procedures each with its result set and i needed to return all the result sets as a single list. – Clinton Okorie Mar 20 '19 at 14:02
  • @ClintonOkorie - Sorry, the question why are trying to concatenating different types can't be answered as you wanted the results as a single list. It's like saying "why do you want a single list - it's because I want a single list". What is the reason for wanting to concat/have a single list? – Enigmativity Mar 20 '19 at 22:03
  • @Enigmativity Oh Okay, I understand. – Clinton Okorie Mar 21 '19 at 12:15
  • @ClintonOkorie - And the reason is? – Enigmativity Mar 21 '19 at 12:29
  • @Enigmativity We have different stored procedures, that returns different types of data for a particular customer, We want a situation where we can return all the different types of data with just one call. I found a solution though. I found a way to use a single stored Procedure, to call multiple stored procedures. That way, I have only one list when i call the main stored procedure> – Clinton Okorie Mar 21 '19 at 14:32
  • @ClintonOkorie - There are many other options. How about returning a tuple or a custom type? – Enigmativity Mar 21 '19 at 22:03
  • @Enigmativity I'm open to Ideas, If you can show me, I would be very greatful. – Clinton Okorie Mar 23 '19 at 14:42
  • @ClintonOkorie - Done. – Enigmativity Mar 24 '19 at 00:39

3 Answers3

0

You cannot Concat lists of two different source types. See functions signature:

public static System.Collections.Generic.IEnumerable<TSource> Concat<TSource> 
    (this System.Collections.Generic.IEnumerable<TSource> first, 
     System.Collections.Generic.IEnumerable<TSource> second);

To still do so project each list into some type that share the same base type or interface. Something of the structure:

public interface IInterface {}
public class AgentTermDTO : IInterface {}
public class AgentHospCashPlanDTO : IInterface {}

or a quick and dirty solution (don't go for this one) is to cast each to a collection of objects: list1.Cast<object>().Concate(...)

Gilad Green
  • 36,708
  • 7
  • 61
  • 95
  • I am not sure I really understand the interface method, could you please send me a link or something where i can see an example? – Clinton Okorie Mar 04 '19 at 11:05
  • @ClintonOkorie he's basically saying that you can't directly **concat** 2 list of different types in C#, they need to be of the same type, for that he's using an interface which provides a set of common methods for both `AgentTermDTO` and `AgentHospCashPlanDTO` to implement so that they are common and can be concatenated later. Read more from this [answer](https://stackoverflow.com/q/4597612/7177029) and [Covariance](https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/covariance-contravariance/). – Kunal Mukherjee Mar 04 '19 at 12:16
0

If you would have written the full definition of term and hosp instead of var, you would have written something like:

List<AgentTerm_Result> terms = ...
List<AgentHospCashPlan_Result> hosps = ...

Apparently they are not of the same type. You can only concatenate sequences of similar type. Alas you forgot to write us your classes. If a term and a hosp are related, for instance if they have the same super class, you could cast them to the super class before contatenating:

var result = terms.Cast<CommonSuperClass>()
    .Concat(hosps.Cast<CommonSuperClass>();

This also works if they implement the same interface.

If there is nothing common between them, then maybe you should reconsider the idea about concatenating these two lists. After all, what is the use of the collection of Cows mixed with a collection of NewYorkCityBuildings?

Anyway, if you really think there is something common, there are several solutions to concatenate the sequences. Of course you can only use the properties they have in common.

Consider creating an interface that contains the properties that you want to access:

interface IMyInterface
{
     // Properties that are both in AgentTerm_Result and in AgentHospCashPlan
     int Id {get;}
     string Name {get;}
}

class AgentTerm_Result : IMyInterface {...}
class AgentHospCashPlan : IMyInterface{...}

var result = terms.Cast<IMyInterface>()
     .Concat(hosps.Cast<IMyInterface>();

If there are no common properties, consider creating a wrapper class that converts the properties to the proper ones:

class AgentTerm : IMyInterface
{
     public AgentTerm_Result TermResult {get; set;}

     public int Id => this.TermResult.TermResultId;
     public string Name => this.TermResult.TermResultName;

}

and similar for Hosp

IEnumerable<IMyInterface> myTerms = terms.Select(term => new AgentTerm
    {
         TermResult = term,
    })
    .Cast<IMyInterface>();
IEnumerable<IMyInterface> myHosps = hosps.Select(hosp => new MyHosp
    {
        Hosp = hosp,
    })
    .Cast<IMyInterface>();

var result = myTerms.Concat(myHosps);
Harald Coppoolse
  • 28,834
  • 7
  • 67
  • 116
0

If you want to return two lists containing two different types, the best option is to return a custom type or even just return a tuple.

To return a custom type, just define up a class to hold the return values:

public class Results
{
    public List<AgentTerm_Result> AgentTerms;
    public List<AgentHospCashPlan_Result> AgentHospCashPlan;
}

Now you can easily do this:

public Results GetResults()
{
    var term = dc.AgentTerm(Agentcode).ToList();
    var hosp = dc.AgentHospCashPlan(Agentcode).ToList();

    return new Results { AgentTerms = term, AgentHospCashPlan = hosp };
}

To use a tuple is slightly easier as you don't need to define anything new:

public (List<AgentTerm_Result>, List<AgentHospCashPlan_Result>) GetResults()
{
    var Agentcode = "";

    var term = dc.AgentTerm(Agentcode).ToList();
    var hosp = dc.AgentHospCashPlan(Agentcode).ToList();

    return (term, hosp);
}   

To get the results of the tuple just call it like this:

var (term, hop) = GetResults();

Then you can use the results as two separate variables.

Enigmativity
  • 113,464
  • 11
  • 89
  • 172
  • Thanks, Would try them both. A quick question, Lets assume both lists have a Field called "Date Created", Would it be possible to sort the values in the list as one, in descending order of date created, Irrespective of which list the values belong to?? – Clinton Okorie Mar 25 '19 at 06:08
  • @ClintonOkorie - I'm not sure what you mean by "sort the values in the list as one". You have two lists, not one, and that means that they can have different numbers of elements. – Enigmativity Mar 25 '19 at 10:43
  • I understand they are two lists,Just trying to figure out, If there is a way to sort the two lists together as if it was a single list. My apologies if my questions are much, I'm new to this. – Clinton Okorie Mar 25 '19 at 12:15
  • @ClintonOkorie - What does it mean to "sort the two lists together as if it was a single list"? – Enigmativity Mar 25 '19 at 23:36