Perf for EMC
This commit is contained in:
parent
6724b4d796
commit
730646c301
|
|
@ -3,8 +3,10 @@
|
|||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Microsoft.AspNetCore.Routing
|
||||
{
|
||||
|
|
@ -24,6 +26,7 @@ namespace Microsoft.AspNetCore.Routing
|
|||
public static readonly EndpointMetadataCollection Empty = new EndpointMetadataCollection(Array.Empty<object>());
|
||||
|
||||
private readonly object[] _items;
|
||||
private readonly ConcurrentDictionary<Type, object[]> _cache;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new <see cref="EndpointMetadataCollection"/>.
|
||||
|
|
@ -37,6 +40,7 @@ namespace Microsoft.AspNetCore.Routing
|
|||
}
|
||||
|
||||
_items = items.ToArray();
|
||||
_cache = new ConcurrentDictionary<Type, object[]>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -67,18 +71,23 @@ namespace Microsoft.AspNetCore.Routing
|
|||
/// <returns>
|
||||
/// The most significant metadata of type <typeparamref name="T"/> or <c>null</c>.
|
||||
/// </returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public T GetMetadata<T>() where T : class
|
||||
{
|
||||
for (var i = _items.Length - 1; i >= 0; i--)
|
||||
if (_cache.TryGetValue(typeof(T), out var result))
|
||||
{
|
||||
var item = _items[i] as T;
|
||||
if (item != null)
|
||||
{
|
||||
return item;
|
||||
}
|
||||
var length = result.Length;
|
||||
return length > 0 ? (T)result[length - 1] : default;
|
||||
}
|
||||
|
||||
return default;
|
||||
return GetMetadataSlow<T>();
|
||||
}
|
||||
|
||||
private T GetMetadataSlow<T>() where T : class
|
||||
{
|
||||
var array = GetOrderedMetadataSlow<T>();
|
||||
var length = array.Length;
|
||||
return length > 0 ? array[length - 1] : default;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -87,16 +96,32 @@ namespace Microsoft.AspNetCore.Routing
|
|||
/// </summary>
|
||||
/// <typeparam name="T">The type of metadata.</typeparam>
|
||||
/// <returns>A sequence of metadata items of <typeparamref name="T"/>.</returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public IEnumerable<T> GetOrderedMetadata<T>() where T : class
|
||||
{
|
||||
if (_cache.TryGetValue(typeof(T), out var result))
|
||||
{
|
||||
return (T[])result;
|
||||
}
|
||||
|
||||
return GetOrderedMetadataSlow<T>();
|
||||
}
|
||||
|
||||
private T[] GetOrderedMetadataSlow<T>() where T : class
|
||||
{
|
||||
var items = new List<T>();
|
||||
for (var i = 0; i < _items.Length; i++)
|
||||
{
|
||||
var item = _items[i] as T;
|
||||
if (item != null)
|
||||
{
|
||||
yield return item;
|
||||
items.Add(item);
|
||||
}
|
||||
}
|
||||
|
||||
var array = items.ToArray();
|
||||
_cache.TryAdd(typeof(T), array);
|
||||
return array;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
|||
|
|
@ -44,5 +44,98 @@ namespace Microsoft.AspNetCore.Routing
|
|||
value => Assert.Equal(2, value),
|
||||
value => Assert.Equal(3, value));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetMetadata_Match_ReturnsLastMatchingEntry()
|
||||
{
|
||||
// Arrange
|
||||
var items = new object[]
|
||||
{
|
||||
new Metadata1(),
|
||||
new Metadata2(),
|
||||
new Metadata3(),
|
||||
};
|
||||
|
||||
var metadata = new EndpointMetadataCollection(items);
|
||||
|
||||
// Act
|
||||
var result = metadata.GetMetadata<IMetadata5>();
|
||||
|
||||
// Assert
|
||||
Assert.Same(items[1], result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetMetadata_NoMatch_ReturnsNull()
|
||||
{
|
||||
// Arrange
|
||||
var items = new object[]
|
||||
{
|
||||
new Metadata3(),
|
||||
new Metadata3(),
|
||||
new Metadata3(),
|
||||
};
|
||||
|
||||
var metadata = new EndpointMetadataCollection(items);
|
||||
|
||||
// Act
|
||||
var result = metadata.GetMetadata<IMetadata5>();
|
||||
|
||||
// Assert
|
||||
Assert.Null(result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetOrderedMetadata_Match_ReturnsItemsInAscendingOrder()
|
||||
{
|
||||
// Arrange
|
||||
var items = new object[]
|
||||
{
|
||||
new Metadata1(),
|
||||
new Metadata2(),
|
||||
new Metadata3(),
|
||||
};
|
||||
|
||||
var metadata = new EndpointMetadataCollection(items);
|
||||
|
||||
// Act
|
||||
var result = metadata.GetOrderedMetadata<IMetadata5>();
|
||||
|
||||
// Assert
|
||||
Assert.Collection(
|
||||
result,
|
||||
i => Assert.Same(items[0], i),
|
||||
i => Assert.Same(items[1], i));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetOrderedMetadata_NoMatch_ReturnsEmpty()
|
||||
{
|
||||
// Arrange
|
||||
var items = new object[]
|
||||
{
|
||||
new Metadata3(),
|
||||
new Metadata3(),
|
||||
new Metadata3(),
|
||||
};
|
||||
|
||||
var metadata = new EndpointMetadataCollection(items);
|
||||
|
||||
// Act
|
||||
var result = metadata.GetOrderedMetadata<IMetadata5>();
|
||||
|
||||
// Assert
|
||||
Assert.Empty(result);
|
||||
}
|
||||
|
||||
private interface IMetadata1 { }
|
||||
private interface IMetadata2 { }
|
||||
private interface IMetadata3 { }
|
||||
private interface IMetadata4 { }
|
||||
private interface IMetadata5 { }
|
||||
private class Metadata1 : IMetadata1, IMetadata4, IMetadata5 { }
|
||||
private class Metadata2 : IMetadata2, IMetadata5 { }
|
||||
private class Metadata3 : IMetadata3 { }
|
||||
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue