I am currently working on code that is using dynamic-linq, I ran into a problem when using a List<BaseClass>
, where the list actually contains a list of the Person
Class.
When I execute the following code I get a ParseException
:
var list = new List<BaseClass>();
list.Add(new Person
{
FirstName = "Joe",
Surname = "Bloggs"
});
list.Where("FirstName == @0", "Joe");
And the Exception:
Please see BaseClass
below:
public class BaseClass
{
public int Id { get; set; }
}
And the Person
class:
public class Person : BaseClass
{
public string FirstName { get; set; }
public string Surname { get; set; }
}
I can overcome the error by implementing the following code:
var list = new List<BaseClass>();
list.Add(new Person
{
FirstName = "Joe",
Surname = "Bloggs"
});
var newList = CreateListOfCorrectType<BaseClass>(list);
newList.Where("FirstName == @0", "Joe");
Please see CreateListOfCorrectType<T>
method below:
private IList CreateListOfCorrectType<T>(
List<T> list)
{
if (list.Count == 0)
{
return list;
}
var typeInfo = list.FirstOrDefault().GetType();
var correctListType = typeof(List<>).MakeGenericType(typeInfo.UnderlyingSystemType);
var listOfCorrectType = (Activator.CreateInstance(correctListType)) as IList;
list.ForEach(x => listOfCorrectType.Add(x));
return listOfCorrectType;
}
My Question is if using the CreateListOfCorrectType
is the best way of overcoming the issue? and if not what alternatives do I have in getting the List<BaseClass>
to the correct Type.
I am looking to use this with existing code, and changing the existing List<>
types are not possible. And the CreateListOfCorrectType
method is not aware of the Person
class.
Please note that class names and variables are for demonstrative purposes only.
UPDATE
Optimist's answer below leaded me to the solution for my issue, please see extension method used below:
public static IList ToDerivedListType(this IList list)
{
if (list == null || list.Count == 0)
{
return list;
}
var type = list.Cast<object>().FirstOrDefault().GetType();
var castedList = typeof(Enumerable).GetMethod("Cast", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public)
.MakeGenericMethod(type)
.Invoke(null, new[] { list });
return typeof(Enumerable).GetMethod("ToList", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public)
.MakeGenericMethod(type)
.Invoke(null, new[] { castedList }) as IList;
}
System.Linq.Enumerable.Cast
and MakeGenericMethod
was the key.
depending on the actual use cases, some things can be improved:
CreateListOfCorrectType
function copies all elements into a new collection which results in unnecessary expense in case only a subset is taken out of the returned collection .IEnumerable
.System.Linq.Enumerable.Cast
andMakeGenericMethod
can be employed to achieve that:If tried to mimic the function you showed in terms of exceptions thrown. There is a difference because the casting is done after the mapping function returns.