0

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?

abatishchev
  • 98,240
  • 88
  • 296
  • 433
Obi
  • 3,091
  • 4
  • 34
  • 56
  • The `Guid` data type cannot be `const`, see: http://stackoverflow.com/questions/4926573/how-to-declare-a-constant-guid-in-c – Matthew Apr 28 '15 at 15:56
  • You can't call `filter.Contains(guid)` either way. But `filter.Any(f => f.Id == guid)`. – abatishchev Apr 28 '15 at 15:57
  • @abatishchev how do you recommend I convert this to a List filter.SetOperand.Select(x => Expression.Constant(Guid.Parse(x.Id))); Which is required for Epression.NewArrayInit. Or are you recommending a totally different approach? – Obi Apr 28 '15 at 16:15
  • What is the type of `SomeObj.id`? Is it string containing guid or System.Guid? – abatishchev Apr 28 '15 at 16:18
  • You can also use `filter.Select(f => f.id).Contains(guid)` but it would be less efficient I think. – abatishchev Apr 28 '15 at 16:19
  • SomeObj.Id is a System.Guid – Obi Apr 28 '15 at 16:21

1 Answers1

2

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)
    
svick
  • 236,525
  • 50
  • 385
  • 514
  • I strongly suspected this would be the case as I have since juggled my code around to almost look like what you have here but this has answered all the nagging questions I had. I will try it when I get in. Thanks – Obi Apr 29 '15 at 04:41