Expression of Type 'System.Int32' Cannot Be Used for Return Type 'System.Object'

Expression of type 'System.Int32' cannot be used for return type 'System.Object'

Have you tried using Expression.Convert? That will add the boxing/lifting/etc conversion.

Expression conversion = Expression.Convert(expression, typeof(object));
func = Expression.Lambda<Func<T, Object>>(conversion, parameterExpression).Compile();

Convert ExpressionFuncTDocument, object to ExpressionFuncTDocument, TOutput

You just need to wrap the original expression's Body in a Convert expression and then rebuild your lambda. Here's how I would do it if I could use generics:

Expression<Func<TInput, TReturn>> ConvertReturnValue<TInput, TReturn>(
Expression<Func<TInput, object>> inputExpression)
{
Expression convertedExpressionBody = Expression.Convert(
inputExpression.Body, typeof(TReturn)
);

return Expression.Lambda<Func<TInput, TReturn>>(
convertedExpressionBody, inputExpression.Parameters
);
}

Usage:

Expression<Func<TDocument, object>> inputExpression = d => d.Name;

Expression<Func<TDocument, string>> convertedExpression
= ConvertReturnValue<TDocument, string>(inputExpression);

// Test.
TDocument doc = new TDocument { Name = "Zzz" };
string name = convertedExpression.Compile().Invoke(doc);

Assert.Equal("Zzz", name);

No generics

If you cannot use generics because you don't know the return type at compile time, Expression.Lambda actually offers a non-generic overload, which you can use like this:

Expression ConvertReturnValue<TInput>(Expression<Func<TInput, object>> inputExpression, Type returnType)
{
Expression convertedExpressionBody = Expression.Convert(inputExpression.Body, returnType);

return Expression.Lambda(convertedExpressionBody, inputExpression.Parameters);
}

The above still returns an Expression<Func<TInput, TReturn>> (upcast to a non-generic Expression). You can downcast it later if you need to:

Expression<Func<TDocument, object>> inputExpression = d => d.Name;

Expression<Func<TDocument, string>> convertedExpression
= (Expression<Func<TDocument, string>>)ConvertReturnValue(inputExpression, typeof(string));

// Test.
TDocument doc = new TDocument { Name = "Zzz" };
string name = convertedExpression.Compile().Invoke(doc);

Assert.Equal("Zzz", name);

Addendum

Note that for struct return types, the final expression may end up looking like this:

(TDocument d) => (int)(object)d.ID;

Expression of type 'System.Int64' cannot be used for return type 'System.Object'

Depending on how you use result you could create it dynamically with the delegate type Func<Entity, long> and type it as a LambdaExpression:

ParameterExpression entityParameter = Expression.Parameter(typeof(Entity), "e");
Expression propertyAccess = Expression.Property(entityParameter, property);
var funcType = typeof(Func<,>).MakeGenericType(typeof(Entity), property.PropertyType);
LambdaExpression result = Expression.Lambda(funcType, propertyAccess, entityParameter);

Expression of type 'System.Int32' cannot be used for parameter of type 'System.Object' of method 'Boolean Equals(System.Object)'

EDIT

Found the solution in this question. You need to convert the expression to Object before calling the Equals(object)method:

var converted = Expression.Convert(searchExpression, typeof(object));
body = Expression.Call(propertyExpression, containsMethod, converted);

Nicodemus13's suggestion of explicitly setting searchExpression's type to Object in the first place should work, too.

Original

I haven't found the issue yet, but I have reproduced the problem in a SSCCE using Linqpad:

void Main()
{
var myInstance = new myClass();
var equalsMethod = typeof(Int32?).GetMethod("Equals", new[] { typeof(Int32?) });
int? nullableInt = 1;
var nullableIntExpr = System.Linq.Expressions.Expression.Constant(nullableInt);
var myInstanceExpr = System.Linq.Expressions.Expression.Constant(myInstance);
var propertyExpr = System.Linq.Expressions.Expression.Property(myInstanceExpr, "MyProperty");
var result = Expression.Call(propertyExpr,equalsMethod,nullableIntExpr); // This line throws the exception.
Console.WriteLine(result);
}

class myClass{public int? MyProperty{get;set;}}

This line:

containsMethod = typeof(Int32?).GetMethod("Equals", new[] { typeof(Int32?) });

returns a MethodInfo for the method Int32?.Equals (Object other). Notice the parameter type is object, not Int32 (or Int32?) as you might expect.

The reason is typeof(Int32?) is System.Nullable<Int32>, which only has the Equals(object) method.

Expression of type 'System.Int16' cannot be used for return type 'System.Object'

The problem here is that <Tprop> is not of the Type Int16 and the string you are passing which is a columnname of the type Int16

You can simply specify the <Tprop> wherever you are calling the function SelectAdmin<TProp>.

for example:

`SelectAdmin<int>(.......your parameters here);`

if the sSortExpression is of the Type int16.
If it is of the type DateTime you can call like this

 SelectAdmin<DateTime>(.......your parameters here);

Expression of type 'System.DateTime' cannot be used for return type 'System.Object'

Just add a conversion in there:

Expression<Func<MyEntity, object>> sortExpression =
Expression.Lambda<Func<AMyEntity, object>>(
Expression.Convert(
Expression.Property(param, sortKey),
typeof(object)),
param);

Expression of type 'System.Func`2[T,System.Boolean]' cannot be used for return type 'System.Boolean'

Not sure what the serializedText is in your snippet, but as long as it is a LambdaExpression which returns a boolean you should be able to do the below.

  Expression expression = Expression.Lambda(Expression.Constant(true), Expression.Parameter(typeof(string)));

Expression<Func<string, bool>> typedExpression = (Expression<Func<string, bool>>)(expression);

Console.WriteLine(typedExpression.Compile().Invoke("Hello"));

replace string with your generic type.

In your example, if the serializedText can be deserialized into a Expression the below should work, you would have to change it for your considerations.

Expression<Func<T, bool>> typedExpression = (Expression<Func<T, bool>>)Expression.Lambda(
serializer.DeserializeText(serializedText),
Expression.Parameter(typeof(T)));

Building a Linq sort expression from string results in 'Expression of system.int32 can not be used for return type System.Object '

It seems like this is ultimately a minor mistake.

  1. You're trying to order by the Expression<Func<T, object>> (as in the value of that, not the value of randomNumber determines the sort order.
  2. .OrderBy for enumerables (not queryables) expects a Func<TSource, TKey> where TSource is OrderEntity and TKey is supposed to be your object value in this case.

So we need to do two things:

  1. Compile the expression.
  2. Use it for sorting.

Essentially we need this

Func<OrderEntity, object> sortAccessor = ToLambda<OrderEntity>(propertyForExpression).Compile();
var sortedOrders = orders.OrderBy(sortAccessor);

or

Func<OrderEntity, object> sortAccessor = ToLambda<OrderEntity>(propertyForExpression).Compile();
var sortedOrders = orders.OrderBy(x => sortAccessor(x));

or

var sortedOrders = orders.OrderBy(x => ToLambda<OrderEntity>(propertyForExpression).Compile()(x));

or

var sortedOrders = orders.OrderBy(ToLambda<OrderEntity>(propertyForExpression).Compile());

You could also change the method to return the compiled Func<T, object> instead:

static Expression<Func<T, object>> ToLambda<T>(string propertyName)
{
var propertyNames = propertyName.Split('.');
var parameter = Expression.Parameter(typeof(T));
Expression body = parameter;
foreach (var propName in propertyNames)
body = Expression.Property(body, propName);

var convertedResult = Expression.Convert(body, typeof(object));

var func = Expression.Lambda<Func<T, object>>(convertedResult, parameter);
return func;
}

and then use it more like this:

Func<OrderEntity, object> sortAccessor = ToLambda<OrderEntity>(propertyForExpression);
var sortedOrders = orders.OrderBy(sortAccessor);

or this:

var sortedOrders = orders.OrderBy(ToLambda<OrderEntity>(propertyForExpression));

Note: the reason I'm suggesting compiling the expression outside of the loop and caching it as a Func<OrderEntity, object> variable is because otherwise it will be evaluated multiple times for a single .OrderBy.



Related Topics



Leave a reply



Submit