0

I'm using LINQ expressions to dynamically search for values in a collection and I've come across a strange issue that seems to be caused by searching for a string that is the result of a String.Format() operation.

Here is a simplified version of what I am trying to do, since in practice I do not actually know what type of value I am searching for, I have to treat everything as an Object.

Dim stringToFind As String = "Some Special Value"

' Create a collection of 10 strings, one of which being the string to find '
Dim myStrings As New List(Of Object)
For i As Integer = 0 To 9
    If (i = 3) Then
        myStrings.Add(String.Format(stringToFind))
    Else
        myStrings.Add("Boring Plain Old Value")
    End If
Next

' Create the predicate for <Function(x) x = stringToFind> '
Dim left = Expression.Parameter(GetType(Object), "x")
Dim right = Expression.Constant(stringToFind)
Dim eq = Expression.Equal(left, right)
Dim predicate = Expression.Lambda(Of Func(Of Object, Boolean))(eq, left).Compile()

' Compare the results '
Dim standardResults = myStrings.Where(Function(x) x = stringToFind)
Dim expressionResults = myStrings.Where(predicate)

' Expected Output:'
' Standard Method: 1 '
' LINQ Expressions: 1 '
Console.WriteLine(String.Format("Standard Method: {0}", standardResults.Count()))
Console.WriteLine(String.Format("LINQ Expressions: {0}", expressionResults.Count()))
Console.ReadLine()

What happens here is that the standard method correctly returns 1 result, while the LINQ Expressions method returns 0. However, if the special value is added to the collection without using String.Format() (myStrings.Add(stringToFind)) then the expression returns the correct result as well.

Is there something that String.Format() does to change the encoding of the string, or anything that would effect how a constant expression is created for the string value? Is there another way I could compare two values using LINQ expressions that would get me around this limitation?

sehe
  • 374,641
  • 47
  • 450
  • 633
mclark1129
  • 7,532
  • 5
  • 48
  • 84
  • Every string is the same. It does not magically get altered by String.Format(). – usr Jul 12 '12 at 16:16

1 Answers1

1

The VB.NET equality operator does not do a reference comparison. Roughly speaking, it uses the object.Equals method (in contrast to object.ReferenceEquals). Expression trees use object reference equality.

Using string.Format does not do anything special. (There are no "special" strings).

usr
  • 168,620
  • 35
  • 240
  • 369
  • Maybe not, but there obviously has to be some difference between String.Format(stringToFind) and stringToFind, otherwise both scenarios would produce the same result. Are you saying that String.Format(stringToFind) generates a new instance of a string so that the ExpressionEquals evaluates to false? – mclark1129 Jul 12 '12 at 17:07
  • @MikeC, yes exactly. The new instance of this particular string reference-compares as false. – usr Jul 12 '12 at 17:19
  • Thanks, I was able to use an overload to Expression.Call to specify using the Object.Equals method instead of Object.ReferenceEquals - Expression.Equal(left, right, False, GetType(Object).GetMethod("Equals", {GetType(Object), GetType(Object)})) and that did the trick! – mclark1129 Jul 12 '12 at 19:07