Skip to content

Commit

Permalink
Merge pull request #429 from jaredpar/cast
Browse files Browse the repository at this point in the history
Add CastUp and CastArray to ImmutableArray<T>
  • Loading branch information
jaredpar committed Jan 27, 2015
2 parents 74aa2bb + 2a73b99 commit dbfb49b
Show file tree
Hide file tree
Showing 3 changed files with 108 additions and 22 deletions.
Expand Up @@ -357,22 +357,6 @@ public static ImmutableArray<T> Create<T>(ImmutableArray<T> items, int start, in
return new ImmutableArray<TResult>(array);
}

/// <summary>
/// Initializes a new instance of the <see cref="ImmutableArray"/> struct based on the contents
/// of an existing instance, allowing a covariant static cast to efficiently reuse the existing array.
/// </summary>
/// <param name="items">The array to initialize the array with. No copy is made.</param>
/// <remarks>
/// Covariant upcasts from this method may be reversed by calling the
/// <see cref="ImmutableArray&lt;T&gt;.As&lt;TOther&gt;"/> instance method.
/// </remarks>
[Pure]
public static ImmutableArray<T> Create<T, TDerived>(ImmutableArray<TDerived> items)
where TDerived : class, T
{
return new ImmutableArray<T>(items.array);
}

/// <summary>
/// Initializes a new instance of the <see cref="ImmutableArray&lt;T&gt;.Builder"/> class.
/// </summary>
Expand Down
Expand Up @@ -1028,6 +1028,33 @@ public bool Equals(ImmutableArray<T> other)
return this.array == other.array;
}

/// <summary>
/// Initializes a new instance of the <see cref="ImmutableArray{T}"/> struct based on the contents
/// of an existing instance, allowing a covariant static cast to efficiently reuse the existing array.
/// </summary>
/// <param name="items">The array to initialize the array with. No copy is made.</param>
/// <remarks>
/// Covariant upcasts from this method may be reversed by calling the
/// <see cref="ImmutableArray{T}.As{TOther};"/> or <see cref="ImmutableArray{T}.CastArray{TOther}"/>method.
/// </remarks>
[Pure]
public static ImmutableArray<T> CastUp<TDerived>(ImmutableArray<TDerived> items)
where TDerived : class, T
{
return new ImmutableArray<T>(items.array);
}

/// <summary>
/// Initializes a new instance of the <see cref="ImmutableArray{T}"/> struct by casting the underlying
/// array to an array of type <typeparam name="TOther"/>.
/// </summary>
/// <exception cref="InvalidCastException">Thrown if the cast is illegal.</exception>
[Pure]
public ImmutableArray<TOther> CastArray<TOther>() where TOther : class
{
return new ImmutableArray<TOther>((TOther[])(object)array);
}

/// <summary>
/// Creates an immutable array for this array, cast to a different element type.
/// </summary>
Expand Down
87 changes: 81 additions & 6 deletions src/System.Collections.Immutable/tests/ImmutableArrayTest.cs
Expand Up @@ -292,22 +292,22 @@ public void CovarianceImplicit()
}

[Fact]
public void CreateByCovariantStaticCast()
public void CastUpReference()
{
ImmutableArray<string> derivedImmutable = ImmutableArray.Create("a", "b", "c");
ImmutableArray<object> baseImmutable = ImmutableArray.Create<object, string>(derivedImmutable);
ImmutableArray<object> baseImmutable = ImmutableArray<object>.CastUp(derivedImmutable);
Assert.Equal(derivedImmutable, baseImmutable);

// Make sure we can reverse that, as a means to verify the underlying array is the same instance.
ImmutableArray<string> derivedImmutable2 = baseImmutable.As<string>();
Assert.Equal(derivedImmutable, derivedImmutable2);
Assert.Equal(derivedImmutable, baseImmutable.As<string>());
Assert.Equal(derivedImmutable, baseImmutable.CastArray<string>());
}

[Fact]
public void CreateByCovariantStaticCastDefault()
public void CastUpReferenceDefaultValue()
{
ImmutableArray<string> derivedImmutable = default(ImmutableArray<string>);
ImmutableArray<object> baseImmutable = ImmutableArray.Create<object, string>(derivedImmutable);
ImmutableArray<object> baseImmutable = ImmutableArray<object>.CastUp(derivedImmutable);
Assert.True(baseImmutable.IsDefault);
Assert.True(derivedImmutable.IsDefault);

Expand All @@ -317,6 +317,81 @@ public void CreateByCovariantStaticCastDefault()
Assert.True(derivedImmutable == derivedImmutable2);
}

[Fact]
public void CastUpRefToInterface()
{
var stringArray = ImmutableArray.Create("a", "b");
var enumArray = ImmutableArray<IEnumerable>.CastUp(stringArray);
Assert.Equal(2, enumArray.Length);
Assert.Equal(stringArray, enumArray.CastArray<string>());
Assert.Equal(stringArray, enumArray.As<string>());
}

[Fact]
public void CastUpInterfaceToInterface()
{
var genericEnumArray = ImmutableArray.Create<IEnumerable<int>>(new List<int>(), new List<int>());
var legacyEnumArray = ImmutableArray<IEnumerable>.CastUp(genericEnumArray);
Assert.Equal(2, legacyEnumArray.Length);
Assert.Equal(genericEnumArray, legacyEnumArray.As<IEnumerable<int>>());
Assert.Equal(genericEnumArray, legacyEnumArray.CastArray<IEnumerable<int>>());
}

[Fact]
public void CastUpArrayToSystemArray()
{
var arrayArray = ImmutableArray.Create(new int[] { 1, 2 }, new int[] { 3, 4 });
var sysArray = ImmutableArray<Array>.CastUp(arrayArray);
Assert.Equal(2, sysArray.Length);
Assert.Equal(arrayArray, sysArray.As<int[]>());
Assert.Equal(arrayArray, sysArray.CastArray<int[]>());
}

[Fact]
public void CastUpArrayToObject()
{
var arrayArray = ImmutableArray.Create(new int[] { 1, 2 }, new int[] { 3, 4 });
var objArray = ImmutableArray<object>.CastUp(arrayArray);
Assert.Equal(2, objArray.Length);
Assert.Equal(arrayArray, objArray.As<int[]>());
Assert.Equal(arrayArray, objArray.CastArray<int[]>());
}

[Fact]
public void CastUpDelegateToSystemDelegate()
{
var delArray = ImmutableArray.Create<Action>(() => { }, () => { });
var sysDelArray = ImmutableArray<Delegate>.CastUp(delArray);
Assert.Equal(2, sysDelArray.Length);
Assert.Equal(delArray, sysDelArray.As<Action>());
Assert.Equal(delArray, sysDelArray.CastArray<Action>());
}

[Fact]
public void CastArrayUnrelatedInterface()
{
var strArray = ImmutableArray.Create<string>("cat", "dog");
var compArray = ImmutableArray<IComparable>.CastUp(strArray);
var enumArray = compArray.CastArray<IEnumerable>();
Assert.Equal(2, enumArray.Length);
Assert.Equal(strArray, enumArray.As<string>());
Assert.Equal(strArray, enumArray.CastArray<string>());
}

[Fact]
public void CastArrayBadInterface()
{
var formattableArray = ImmutableArray.Create<IFormattable>(1, 2);
Assert.Throws(typeof(InvalidCastException), () => formattableArray.CastArray<IComparable>());
}

[Fact]
public void CastArrayBadRef()
{
var objArray = ImmutableArray.Create<object>("cat", "dog");
Assert.Throws(typeof(InvalidCastException), () => objArray.CastArray<string>());
}

[Fact]
public void ToImmutableArray()
{
Expand Down

0 comments on commit dbfb49b

Please sign in to comment.