Skip to content
This repository was archived by the owner on Nov 20, 2018. It is now read-only.

Commit d17d915

Browse files
committed
1 parent 39c2535 commit d17d915

File tree

2 files changed

+272
-1
lines changed

2 files changed

+272
-1
lines changed

src/Microsoft.AspNetCore.Http.Abstractions/Routing/RouteValueDictionary.cs

+44-1
Original file line numberDiff line numberDiff line change
@@ -388,19 +388,62 @@ public bool Remove(string key)
388388
return false;
389389
}
390390

391-
EnsureCapacity(Count);
391+
// Ensure property storage is converted to array storage as we'll be
392+
// applying the lookup and removal on the array
393+
EnsureCapacity(_count);
394+
395+
var index = FindIndex(key);
396+
if (index >= 0)
397+
{
398+
_count--;
399+
var array = _arrayStorage;
400+
Array.Copy(array, index + 1, array, index, _count - index);
401+
array[_count] = default;
402+
403+
return true;
404+
}
405+
406+
return false;
407+
}
408+
409+
/// <summary>
410+
/// Attempts to remove and return the value that has the specified key from the <see cref="RouteValueDictionary"/>.
411+
/// </summary>
412+
/// <param name="key">The key of the element to remove and return.</param>
413+
/// <param name="value">When this method returns, contains the object removed from the <see cref="RouteValueDictionary"/>, or <c>null</c> if key does not exist.</param>
414+
/// <returns>
415+
/// <c>true</c> if the object was removed successfully; otherwise, <c>false</c>.
416+
/// </returns>
417+
public bool Remove(string key, out object value)
418+
{
419+
if (key == null)
420+
{
421+
ThrowArgumentNullExceptionForKey();
422+
}
423+
424+
if (_count == 0)
425+
{
426+
value = default;
427+
return false;
428+
}
429+
430+
// Ensure property storage is converted to array storage as we'll be
431+
// applying the lookup and removal on the array
432+
EnsureCapacity(_count);
392433

393434
var index = FindIndex(key);
394435
if (index >= 0)
395436
{
396437
_count--;
397438
var array = _arrayStorage;
439+
value = array[index].Value;
398440
Array.Copy(array, index + 1, array, index, _count - index);
399441
array[_count] = default;
400442

401443
return true;
402444
}
403445

446+
value = default;
404447
return false;
405448
}
406449

test/Microsoft.AspNetCore.Http.Abstractions.Tests/RouteValueDictionaryTests.cs

+228
Original file line numberDiff line numberDiff line change
@@ -1393,6 +1393,234 @@ public void Remove_ListStorage_True_CaseInsensitive()
13931393
Assert.IsType<KeyValuePair<string, object>[]>(dict._arrayStorage);
13941394
}
13951395

1396+
[Fact]
1397+
public void Remove_KeyAndOutValue_EmptyStorage()
1398+
{
1399+
// Arrange
1400+
var dict = new RouteValueDictionary();
1401+
1402+
// Act
1403+
var result = dict.Remove("key", out var removedValue);
1404+
1405+
// Assert
1406+
Assert.False(result);
1407+
Assert.Null(removedValue);
1408+
}
1409+
1410+
[Fact]
1411+
public void Remove_KeyAndOutValue_EmptyStringIsAllowed()
1412+
{
1413+
// Arrange
1414+
var dict = new RouteValueDictionary();
1415+
1416+
// Act
1417+
var result = dict.Remove("", out var removedValue);
1418+
1419+
// Assert
1420+
Assert.False(result);
1421+
Assert.Null(removedValue);
1422+
}
1423+
1424+
[Fact]
1425+
public void Remove_KeyAndOutValue_PropertyStorage_Empty()
1426+
{
1427+
// Arrange
1428+
var dict = new RouteValueDictionary(new { });
1429+
1430+
// Act
1431+
var result = dict.Remove("other", out var removedValue);
1432+
1433+
// Assert
1434+
Assert.False(result);
1435+
Assert.Null(removedValue);
1436+
Assert.Empty(dict);
1437+
Assert.NotNull(dict._propertyStorage);
1438+
}
1439+
1440+
[Fact]
1441+
public void Remove_KeyAndOutValue_PropertyStorage_False()
1442+
{
1443+
// Arrange
1444+
var dict = new RouteValueDictionary(new { key = "value" });
1445+
1446+
// Act
1447+
var result = dict.Remove("other", out var removedValue);
1448+
1449+
// Assert
1450+
Assert.False(result);
1451+
Assert.Null(removedValue);
1452+
Assert.Collection(dict, kvp => { Assert.Equal("key", kvp.Key); Assert.Equal("value", kvp.Value); });
1453+
Assert.IsType<KeyValuePair<string, object>[]>(dict._arrayStorage);
1454+
}
1455+
1456+
[Fact]
1457+
public void Remove_KeyAndOutValue_PropertyStorage_True()
1458+
{
1459+
// Arrange
1460+
object value = "value";
1461+
var dict = new RouteValueDictionary(new { key = value });
1462+
1463+
// Act
1464+
var result = dict.Remove("key", out var removedValue);
1465+
1466+
// Assert
1467+
Assert.True(result);
1468+
Assert.Same(value, removedValue);
1469+
Assert.Empty(dict);
1470+
Assert.IsType<KeyValuePair<string, object>[]>(dict._arrayStorage);
1471+
}
1472+
1473+
[Fact]
1474+
public void Remove_KeyAndOutValue_PropertyStorage_True_CaseInsensitive()
1475+
{
1476+
// Arrange
1477+
object value = "value";
1478+
var dict = new RouteValueDictionary(new { key = value });
1479+
1480+
// Act
1481+
var result = dict.Remove("kEy", out var removedValue);
1482+
1483+
// Assert
1484+
Assert.True(result);
1485+
Assert.Same(value, removedValue);
1486+
Assert.Empty(dict);
1487+
Assert.IsType<KeyValuePair<string, object>[]>(dict._arrayStorage);
1488+
}
1489+
1490+
[Fact]
1491+
public void Remove_KeyAndOutValue_ListStorage_False()
1492+
{
1493+
// Arrange
1494+
var dict = new RouteValueDictionary()
1495+
{
1496+
{ "key", "value" },
1497+
};
1498+
1499+
// Act
1500+
var result = dict.Remove("other", out var removedValue);
1501+
1502+
// Assert
1503+
Assert.False(result);
1504+
Assert.Null(removedValue);
1505+
Assert.Collection(dict, kvp => { Assert.Equal("key", kvp.Key); Assert.Equal("value", kvp.Value); });
1506+
Assert.IsType<KeyValuePair<string, object>[]>(dict._arrayStorage);
1507+
}
1508+
1509+
[Fact]
1510+
public void Remove_KeyAndOutValue_ListStorage_True()
1511+
{
1512+
// Arrange
1513+
object value = "value";
1514+
var dict = new RouteValueDictionary()
1515+
{
1516+
{ "key", value }
1517+
};
1518+
1519+
// Act
1520+
var result = dict.Remove("key", out var removedValue);
1521+
1522+
// Assert
1523+
Assert.True(result);
1524+
Assert.Same(value, removedValue);
1525+
Assert.Empty(dict);
1526+
Assert.IsType<KeyValuePair<string, object>[]>(dict._arrayStorage);
1527+
}
1528+
1529+
[Fact]
1530+
public void Remove_KeyAndOutValue_ListStorage_True_CaseInsensitive()
1531+
{
1532+
// Arrange
1533+
object value = "value";
1534+
var dict = new RouteValueDictionary()
1535+
{
1536+
{ "key", value }
1537+
};
1538+
1539+
// Act
1540+
var result = dict.Remove("kEy", out var removedValue);
1541+
1542+
// Assert
1543+
Assert.True(result);
1544+
Assert.Same(value, removedValue);
1545+
Assert.Empty(dict);
1546+
Assert.IsType<KeyValuePair<string, object>[]>(dict._arrayStorage);
1547+
}
1548+
1549+
[Fact]
1550+
public void Remove_KeyAndOutValue_ListStorage_KeyExists_First()
1551+
{
1552+
// Arrange
1553+
object value = "value";
1554+
var dict = new RouteValueDictionary()
1555+
{
1556+
{ "key", value },
1557+
{ "other", 5 },
1558+
{ "dotnet", "rocks" }
1559+
};
1560+
1561+
// Act
1562+
var result = dict.Remove("key", out var removedValue);
1563+
1564+
// Assert
1565+
Assert.True(result);
1566+
Assert.Same(value, removedValue);
1567+
Assert.Equal(2, dict.Count);
1568+
Assert.False(dict.ContainsKey("key"));
1569+
Assert.True(dict.ContainsKey("other"));
1570+
Assert.True(dict.ContainsKey("dotnet"));
1571+
Assert.IsType<KeyValuePair<string, object>[]>(dict._arrayStorage);
1572+
}
1573+
1574+
[Fact]
1575+
public void Remove_KeyAndOutValue_ListStorage_KeyExists_Middle()
1576+
{
1577+
// Arrange
1578+
object value = "value";
1579+
var dict = new RouteValueDictionary()
1580+
{
1581+
{ "other", 5 },
1582+
{ "key", value },
1583+
{ "dotnet", "rocks" }
1584+
};
1585+
1586+
// Act
1587+
var result = dict.Remove("key", out var removedValue);
1588+
1589+
// Assert
1590+
Assert.True(result);
1591+
Assert.Same(value, removedValue);
1592+
Assert.Equal(2, dict.Count);
1593+
Assert.False(dict.ContainsKey("key"));
1594+
Assert.True(dict.ContainsKey("other"));
1595+
Assert.True(dict.ContainsKey("dotnet"));
1596+
Assert.IsType<KeyValuePair<string, object>[]>(dict._arrayStorage);
1597+
}
1598+
1599+
[Fact]
1600+
public void Remove_KeyAndOutValue_ListStorage_KeyExists_Last()
1601+
{
1602+
// Arrange
1603+
object value = "value";
1604+
var dict = new RouteValueDictionary()
1605+
{
1606+
{ "other", 5 },
1607+
{ "dotnet", "rocks" },
1608+
{ "key", value }
1609+
};
1610+
1611+
// Act
1612+
var result = dict.Remove("key", out var removedValue);
1613+
1614+
// Assert
1615+
Assert.True(result);
1616+
Assert.Same(value, removedValue);
1617+
Assert.Equal(2, dict.Count);
1618+
Assert.False(dict.ContainsKey("key"));
1619+
Assert.True(dict.ContainsKey("other"));
1620+
Assert.True(dict.ContainsKey("dotnet"));
1621+
Assert.IsType<KeyValuePair<string, object>[]>(dict._arrayStorage);
1622+
}
1623+
13961624
[Fact]
13971625
public void TryAdd_EmptyStringIsAllowed()
13981626
{

0 commit comments

Comments
 (0)