R.Santos
R.Santos

Reputation: 3

Casting error adding Guid value to Dictionary<string, object> inside an IQueryable.Select() lambda expression selector:

The code fragment below uses the IQueryable.Select() method to perform generic property projections on a given query, according to a list of given property names.

The program works fine if all the properties are of type 'string', but it triggers the exception below when some property is of a different type, like 'Guid'.

Expression of type 'System.Guid' cannot be used for parameter of type 'System.Object' of method 'Void Add(System.String, System.Object)

How can I solve this problem?

public static IQueryable SelectProperties<T>(this IQueryable<T> baseQuery, String[] selectedProperties) where T : class 
{
    var parameter = Expression.Parameter(typeof(T), "t");
    var addMethod = typeof(Dictionary<string, object>).GetMethod("Add");
    List<ElementInit> dicadds = new List<ElementInit>();
    foreach (var selectedProperty in selectedProperties)
    {
        var eKey = Expression.Constant(selectedProperty);
        var eValue = Expression.Property(parameter, selectedProperty);
        var eAdd = Expression.ElementInit(addMethod, eKey, eValue);
        dicadds.Add(eAdd);
    }
    var dicinit = Expression.ListInit(Expression.New(typeof(Dictionary<string, object>)), dicadds);
    var selector = Expression.Lambda<Func<T, dynamic>>(dicinit, parameter);
    return baseQuery.Select(selector);
}

Upvotes: 0

Views: 330

Answers (1)

mrfelis
mrfelis

Reputation: 765

The problem happens for all value types. Value types are not objects, but C# is supposed to automatically box value types, but where you are building an expression yourself, you might be bypassing that.

The following change converts everything to object, thus boxing value types.

var eKey = Expression.Constant(selectedProperty);
var eValue = Expression.Property(parameter, selectedProperty);
Expression boxed = Expression.Convert(eValue, typeof(object));
var eAdd = Expression.ElementInit(addMethod, eKey, boxed);
dicadds.Add(eAdd);

Upvotes: 1

Related Questions