yo3hcv
yo3hcv

Reputation: 1669

C#, dynamic linq error No applicable method 'Contains' exists in type 'String'

I have a list of objects like this (I am using .NET 3.5)

public class MyObjects
{
    public object Name { get; set; }
    public bool Case { get; set; }
}

List<MyObjects> test = new List<MyObjects> { 

    new MyObjects { Name = "one" },
    new MyObjects { Name = "two" },
    new MyObjects { Name = "three" },
    new MyObjects { Name = "four" },
    new MyObjects { Name = "one1" },
    new MyObjects { Name = "two1" },
    new MyObjects { Name = "three1" },
    new MyObjects { Name = "four1" },
    new MyObjects { Name = "one2" },
    new MyObjects { Name = "two2" },
    new MyObjects { Name = "three2" },
    new MyObjects { Name = "four2" },
};

Now I try to search in the list using Linq. This is working as expected

var tmp = test
    .Select(p => p.Name)
    .Where(x => x.ToString().Contains("One", StringComparison.InvariantCultureIgnoreCase))
    ;

Using Dynamic Linq, this also works as expected

var dtmp = test.AsQueryable()
    .Select(p => p.Name)
    .Where("ToString().Contains(@0)", "one")
    ;

However, when trying to use case (in)sensitive, the dynamic fails.

var dtmp2 = test.AsQueryable()
    .Select(p => p.Name)
    .Where("ToString().Contains(@0, @1)", "one", StringComparison.InvariantCultureIgnoreCase)
    ;

The error is

No applicable method 'Contains' exists in type 'String'

My first attempt was to write a Contains() extension like this

public static bool Contains(this string source, string toCheck, StringComparison comp)
{
    return source.IndexOf(toCheck, comp) >= 0;
}

Appears that Dynamic Linq isn't aware of my extension. I discovered (according to this) https://social.msdn.microsoft.com/Forums/en-US/39763339-1700-486f-9800-badd257e921e/custom-extension-methods-and-dynamic-linq-dynamic-expression-api?forum=linqprojectgeneral

that Dynamic Linq cannot uses (static) extension very easily.

So either:

  1. Transform extension in a normal method. However, how can I do this for every ToString(), is it possible or should I write a method in MyObject then use linq with specific objects ?

  2. Modify the Dynamic Library code to accept hard coded (my)static extensions.

  3. Other suggestions?

Note: I could use a simple if/else for case sensitive with two dynamics but I prefer to solve the dynamic way since my app use some complex filtering.

Thank you in advance,

Upvotes: 2

Views: 9584

Answers (2)

Stef Heyenrath
Stef Heyenrath

Reputation: 9830

Did you try using System.Linq.Dynamic.Core because it seems that this library can handle your example c# code.

Upvotes: 0

rschoenbach
rschoenbach

Reputation: 535

If your application needs dynamic filter capabilities, I would recommend having the caller pass a predicate.

This allows for a separation of concerns and easier unit testing.

Also, no need for a IF/ELSE statement when the caller passes a predicate.

var predicate = new Predicate<string>(str => str.Contains("one"));

var tmp = test.Select(p => p.Name).Where(predicate);

Upvotes: 1

Related Questions