Obi
Obi

Reputation: 3091

Expression tree yields Argument exception

I have the following piece of code, all works well until I get to the very last line where it fails with the following exception:

Method 'Boolean Contains(System.Linq.Expressions.ConstantExpression)' declared on type 'System.Collections.Generic.List`1[System.Linq.Expressions.ConstantExpression]' cannot be called with instance of type 'System.Guid'

var filter = new List<SomeObj> { new SomeObj { Id = "<guid-string>" }};

var lookupExpression = filter.SetOperand.Select(x => Expression.Constant(Guid.Parse(x.Id))).ToList();
var arrayOfValues = Expression.NewArrayInit(typeof(Guid), lookupExpression);
var arrayType = lookupExpression.GetType();
var containsMethod = arrayType.GetMethod("Contains");

var right = Expression.Call(dataProperty, containsMethod, arrayOfValues);

I think the problem is that dataProperty is read from a dynamically constructed expression which would always be a Guid so when the method executes, it sees this object as a Guid while the method and list are both List. Is there some other way around this?

Upvotes: 0

Views: 762

Answers (1)

svick
svick

Reputation: 245008

I don't quite understand what are you trying to do or why, but here is my guess how to fix your code:

  1. You don't want to check that your collection of expressions of GUIDs (lookupExpression) contains a given GUID, you want to check that your expression of collection of GUIDs (arrayOfValues) does. This means that arrayType is wrong, it should be: var arrayType = arrayOfValues.Type;.
  2. If arrayOfValues is actually meant to be array, you can't use a Contains instance method, because array doesn't have one.

    You can either use LINQ Contains, or change arrayOfValues to be an expression that represents List<Guid> instead of Guid[]. I have chosen LINQ.

    To get the LINQ Contains method, you can use LINQ:

    var containsMethod = typeof(Enumerable).GetMethods()
        .Single(m => m.Name == "Contains" && m.GetParameters().Length == 2)
        .MakeGenericMethod(typeof(Guid));
    
  3. Your Call() is in the wrong order even for List.Contains(). For LINQ Contains, the correct order is:

    Expression.Call(containsMethod, arrayOfValues, dataProperty)
    

Upvotes: 2

Related Questions