I have an object that has 3 separate Dictionaries. The value parameter for each dictionary implements the same interface. What is the best method to combine the 3 dictionaries into one and perform a single query so the results from the query will be a single IEnumerable?
Here’s a rough idea of I am trying to accomplish. My DataSet object contains 3 dictionaries, each of which should be very small (theoretically some could contain up to 100 elements, but except in the most extreme cases they will be always less than 20 and usually 6 or less).
The purpose of the GetAllId() method will be to retrieve the Id for several private fields in each element of each dictionary and return it as a single IEnumerable. The dictionary value objects all implement IIdQueryable, which defines a single method that will extract all of the required Id‘s in the object.
I have 2 different ideas on how to accomplish what I want, but I am not sure if there is a better way to accomplish this?
public class DataSet
{
Dictionary<Int32, Foo> dict1;
Dictionary<CustomKey, Bar> dict2;
Dictionary<Int32, Boo> dict3;
public IEnumerable<Int32> GetAllId
{
// need to retrieve Id from dict1, dict2, and dict3.
// implementation ideas below
}
}
Option 1
public IEnumerable<Int32> GetAllId
{
var q1 = dict.Values.SelectMany(g => g.GetId());
var q2 = dict.Values.SelectMany(g => g.GetId());
var q3 = dict.Values.SelectMany(g => g.GetId());
return q1.Concat(q2).Concat(q3);
}
Option 2
public IEnumerable<Int32> GetAllId
{
var c1 = dict1.Values.Cast<IIdQueryable>();
var c2 = dict2.Values.Cast<IIdQueryable>();
var c3 = dict2.Values.Cast<IIdQueryable>();
var collection = c1.Concat(c2).Concat(c3);
return collection.SelectMany(g => g.GetId());
}
Method #3
Since each object implements the same interface, is it possible to perform a single LINQ query on all 3 objects without casting?
I personally like Method #1 better as it doesn’t involve casting anything, but I think Method #2 seems to be more readable.
If it is needed, here’s a rough idea of how the interface is implemented
public interface IIdQueryable
{
IEnumerable<Int32> GetId();
}
public class Foo : IIdQueryable
{
public IEnumerable<Int32> GetId()
{
//returns Id of all elements in this object
}
}
public class Bar : IGuidQueryable
{
public IEnumerable<Int32> GetId()
{
//returns Id of all elements in this object
}
}
public class Boo : IGuidQueryable
{
public IEnumerable<Int32> GetId()
{
//returns Id of all elements in this object
}
}
EDIT:
The question title is the source of what I was hoping could be done (that is do all 3 lookups in a single query without casting). I clarified that above.
You just need one
SelectManycall in the first approach:Personally I wouldn’t duct-tape this together though, there is no performance impact by keeping the queries separate and just returning the concatenation like you did already in the first example – it is more readable to me:
Now this looks pretty close to the second approach already – but no cast needed.