Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 6 additions & 9 deletions src/libraries/System.Linq/src/System/Linq/OfType.SpeedOpt.cs
Original file line number Diff line number Diff line change
Expand Up @@ -177,15 +177,12 @@ public override IEnumerable<TResult2> Select<TResult2>(Func<TResult, TResult2> s

public override bool Contains(TResult value)
{
// Avoid checking for IList when size-optimized because it keeps IList
// implementations which may otherwise be trimmed. Since List<T> implements
// IList and List<T> is popular, this could potentially be a lot of code.
if (!IsSizeOptimized &&
!typeof(TResult).IsValueType && // don't box TResult
_source is IList list)
{
return list.Contains(value);
}
// It is tempting to delegate here to IList.Contains if _source is IList (especially
// if TResult is not a value type, as it would be boxed as an argument to Contains).
// And while that will be correct in most cases, if any of the items in the source
// compares equally with value but is not actually of type TResult, doing so would
// skip the type check implied by OfType<TResult>(). Further, if IList is a multidim
// array, its IList.Contains will fail for non-1 ranks. We thus just iterate directly.

foreach (object? item in _source)
{
Expand Down
50 changes: 50 additions & 0 deletions src/libraries/System.Linq/tests/OfTypeTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -228,5 +228,55 @@ public void MultipleIterations()
Assert.Equal(i + 1, count);
}
}

[Fact]
public void MultiDimArray_OfType_Succeeds()
{
var array = new string[3, 4];
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 4; j++)
{
array[i, j] = $"{i}{j}";
}
}

// ToArray
var result = array.OfType<string>().ToArray();
Assert.Equal(12, result.Length);
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 4; j++)
{
Assert.Equal($"{i}{j}", result[i * 4 + j]);
}
}

// Contains
foreach (string s in array)
{
Assert.True(array.OfType<string>().Contains(s));
}
}

[Fact]
public void OfType_Contains_FiltersByTypeEvenIfEqual()
{
List<MySneakyObject1> list = [new MySneakyObject1()];
Assert.Empty(list.OfType<MySneakyObject2>());
Assert.False(list.OfType<MySneakyObject2>().Contains(new MySneakyObject2()));
}

private class MySneakyObject1
{
public override bool Equals(object? obj) => obj is MySneakyObject1;
public override int GetHashCode() => 0;
}

private class MySneakyObject2 : MySneakyObject1
{
public override bool Equals(object? obj) => obj is MySneakyObject2;
public override int GetHashCode() => 0;
}
}
}
Loading