I simply want to do this:
(inputObj ) => (inputObj .Select(objEln=> hubObjectConverter(objEln)));
inputObj ----> List<elnObject>
hubObjectConverter ----> Func<object,object>
Where am I going wrong?
var typeElnObjList = typeof(List<>).MakeGenericType(new[] { elnObjectType });
var inputObj = Expression.Parameter(typeElnObjList, "lstElnObj");
var paramSelectMeth = Expression.Parameter(elnObjectType, "objEln");
var convertToObject = Expression.Invoke(Expression.Constant(hubObjectConverter), paramSelectMeth);
var lambdaSelect = Expression.Lambda(convertToObject, paramSelectMeth);
var convertList = Expression.Call(typeof(Enumerable),
"Select",
new[] { elnObjectType, hubObjectType },
inputObj,
lambdaSelect); <------ I keep getting an error here. Saying Select cannot accept generic type. Where am I going wrong?
(I assume your question is an X/Y problem, so I won't answer your question at face-value)
If your intent is to allow converting from a List<TIn>
to a List<TOut>
by specifying the type of TOut
at runtime with a Type
rather than a generic-type parameter then you only need MakeGenericMethod
and you don't need to use Expression<>
at all:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
public static class ListExtensions
{
public static IList ConvertList<TSource>( this List<TSource> source, Type destinationType, Func<object,object> hubObjectConverter )
{
if( source is null ) throw new ArgumentNullException(nameof(source));
if( destinationType is null ) throw new ArgumentNullException(nameof(destinationType));
//
MethodInfo mi = typeof(ListExtensions)
.GetMethod( nameof(ConvertListImpl), BindingFlags.Static | BindingFlags.NonPublic )
.MakeGenericMethod( typeof(TSource), destinationType );
Object result = mi.Invoke( obj: null, new Object[] { source, hubObjectConverter } );
return (IList)result;
}
private static List<TOut> ConvertListImpl<TIn,TOut>( List<TIn> source, Func<Object,Object> converter )
{
return source
.Select( item => converter( item ) )
.Cast<TOut>()
.ToList();
}
}
(To improve performance, the MethodInfo
could be cached in a static readonly ConcurrentDictionary<(TIn,TOut),MethodInfo>
dictionary).
It would be used like so:
List<Int32> listOfInt32 = new List<Int32>() { 1, 2, 3, 4, 5 };
IList listOfString = listOfInt32.ConvertList( destinationType: typeof(String), obj => obj.ToString() );
Even though listOfString
is statically-typed as IList
, its actual runtime type is List<String>
.