Thread safe case insensitive substring match?

M

Marcel Müller

I need to find sub strings case insensitive inside lambda expressions.
Something like:

..Where(obj => obj.StringAttribute.CaseInsensitiveContains(somestring))

There is no case insensitive Contains in framework 3.5, but the class
CompareInfo provides a useful IndexOf:

var ci = CultureInfo.CurrentCulture.CompareInfo;
..Where(obj => ci.IndexOf(obj.StringAttribute, somestring,
CompareOptions.IgnoreCase) >= 0);

Unfortunately the IndexOf method is not marked as thread safe an the
expression tree my be evaluated in background by another thread.

I could lookup the current culture on every comparison, but this has the
side effect of taking the CultureInfo of some worker thread rather than
the owner of the query. Furthermore I am unsure whether calling
CultureInfo.CurrentCulture.CompareInfo some thousand times in a loop is
a good advise. And last but not least I am not able to use a custom
CultureInfo which is not the current CultureInfo of a thread this way.

Is there a way out of this dead end?


Marcel
 
M

Marcel Müller

I need to find sub strings case insensitive inside lambda expressions.
Something like:

..Where(obj => obj.StringAttribute.CaseInsensitiveContains(somestring))

There is no case insensitive Contains in framework 3.5 [...]

Is there a way out of this dead end?

System.String.IndexOf()?
http://msdn.microsoft.com/en-us/library/ms224425.aspx

I haven't looked closely at the CompareInfo.IndexOf() method, so I'm
unfamiliar with the specific lack of thread-safety you're describing.
But System.String is documented as being 100% thread-safe, and IMHO the
String.IndexOf() method is more convenient to use anyway.

Uh, oh, please don't aks me why I did not find this overload of
string.IndexOf.

Btw. it internally calls
CultureInfo.CurrentCulture.CompareInfo.IndexOf(this, value, startIndex,
count, CompareOptions.IgnoreCase);

But I still cannot pass a custom CompareInfo.


Marcel
 
M

Marcel Müller

Do you actually need to use a custom CompareInfo? That's a fairly
unusual scenario.

Currently I started with the default comparer. But there are some
potential issues. First of all it is sensitive to configuration settings
of the web server. This often causes service tickets.
Secondly, it is part of a query provider with an SAP backend. SAP most
likely has it's own NLS comparison rules. Once we run into a different
behavior the application might no longer return some search results,
because what compares equal in SAP might not compare equal in .NET or
vice versa.

As for whether you can or not, I don't see why you can't. I agree that
MSDN documents CompareInfo (like most other .NET types) as being not
thread-safe for instance methods. But that doesn't mean you can't use
them in multi-threaded scenarios. It just means you need to apply your
own thread-safety to the object.

For example, if sharing the object between threads, synchronize that
use. Even better, don't share the object between threads…let each thread
have its own instance.

That's most likely the best solution. I have a shared read only factory
and each thread creates it's own instance in a ThreadStatic field on demand.

Of course, given that String.IndexOf() is calling
CultureInfo.CurrentCulture.CompareInfo.IndexOf() that raises the
observation: either CompareInfo.IndexOf() is thread-safe, at least in
that particular pattern of usage, or String.IndexOf() is not thread-safe
in spite of the documentation.

No there is no such implication. CultureInfo.CurrentCulture returns the
CultureInfo of the current *thread*. So it is most likely a private
instance of the thread, which is obviously thread-safe. Looking at
IndexOf seems to prove this assumption. IndexOf passes a Handle to the
implementing kernel function. So it is most likely not thread save.


Marcel
 
M

Marcel Müller

Instances that need access to shared data (e.g. static variables) may
still be non-thread-safe even when there is one per thread.

Ack. (As long as the static data isn't TLS.)
But there is not any inherent guarantee of thread-safety; absent a
specific claim of documentation, there is no reason to believe that
having a private instance per-thread is "obviously thread-safe".

I should have mentioned that the documentation explicitly guarantees the
concurrent use of different instances of CultureInfo and CompareInfo in
different threads.

Which IndexOf are you talking about? If you are talking about
String.IndexOf, or even CompareInfo.IndexOf as it's used by
System.String, and you believe it to not be thread-safe, then that's a
bug.

CompareInfo.IndexOf of a single CompareInfo instance is not thread-safe.
But String.IndexOf of the same String instance /is/ thread-safe.
The point is that String.IndexOf uses a thread-local CultureInfo instance.
System.String is specifically documented as being thread-safe for
all instance members. If you find something in it that's not, you should
report it as a bug.

Everything is fine so far.


Marcel
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Similar Threads


Top