Last active
August 29, 2015 13:56
-
-
Save Virtlink/9063619 to your computer and use it in GitHub Desktop.
Helper methods for creating nested arrays.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Diagnostics; | |
using System.Linq; | |
namespace Virtlink | |
{ | |
/// <summary> | |
/// Helper methods for creating nested arrays. | |
/// </summary> | |
/// <example> | |
/// Usage example: | |
/// <code> | |
/// int[][][] myArray = (int[][][])NestedArray.Create<int>(10, 5, 3); | |
/// </code> | |
/// </example> | |
/// <remarks> | |
/// Created by Virtlink. Original source code on GitHub: | |
/// <see href="https://gist.github.com/Virtlink/9063619"/>. | |
/// </remarks> | |
public static class NestedArray | |
{ | |
/// <summary> | |
/// Creates a nested array. | |
/// </summary> | |
/// <typeparam name="T">The type of elements in the most nested array.</typeparam> | |
/// <param name="lengths">The length of each level of the nested arrays.</param> | |
/// <returns>The created <see cref="Array"/> object.</returns> | |
public static Array Create<T>(params int[] lengths) | |
{ | |
#region Contract | |
if (lengths == null) throw new ArgumentNullException("lengths"); | |
if (lengths.Length == 0) throw new ArgumentException("Specify at least one length.", "lengths"); | |
if (lengths.Any(v => v < 0)) throw new ArgumentOutOfRangeException("lengths", "The lengths may not be negative."); | |
#endregion | |
return Create(typeof(T), lengths); | |
} | |
/// <summary> | |
/// Creates a nested array. | |
/// </summary> | |
/// <typeparam name="T">The type of elements in the most nested array.</typeparam> | |
/// <param name="lengths">The length of each level of the nested arrays.</param> | |
/// <param name="defaultValue">The default value of the most nested elements.</param> | |
/// <returns>The created <see cref="Array"/> object.</returns> | |
public static Array Create<T>(int[] lengths, T defaultValue) | |
{ | |
#region Contract | |
if (lengths == null) throw new ArgumentNullException("lengths"); | |
if (lengths.Length == 0) throw new ArgumentException("Specify at least one length.", "lengths"); | |
if (lengths.Any(v => v < 0)) throw new ArgumentOutOfRangeException("lengths", "The lengths may not be negative."); | |
#endregion | |
return Create(typeof(T), lengths, (object)defaultValue); | |
} | |
/// <summary> | |
/// Creates a nested array. | |
/// </summary> | |
/// <param name="elementType">The type of elements in the most nested array.</param> | |
/// <param name="lengths">The length of each level of the nested arrays.</param> | |
/// <returns>The created <see cref="Array"/> object.</returns> | |
public static Array Create(Type elementType, params int[] lengths) | |
{ | |
#region Contract | |
if (elementType == null) throw new ArgumentNullException("elementType"); | |
if (lengths == null) throw new ArgumentNullException("lengths"); | |
if (lengths.Length == 0) throw new ArgumentException("Specify at least one length.", "lengths"); | |
if (lengths.Any(v => v < 0)) throw new ArgumentOutOfRangeException("lengths", "The lengths may not be negative."); | |
#endregion | |
return Create(elementType, lengths, null); | |
} | |
/// <summary> | |
/// Creates a nested array. | |
/// </summary> | |
/// <param name="elementType">The type of elements in the most nested array.</param> | |
/// <param name="lengths">The length of each level of the nested arrays.</param> | |
/// <param name="defaultValue">The default value of the most nested elements.</param> | |
/// <returns>The created <see cref="Array"/> object.</returns> | |
public static Array Create(Type elementType, int[] lengths, object defaultValue) | |
{ | |
#region Contract | |
if (elementType == null) throw new ArgumentNullException("elementType"); | |
if (lengths == null) throw new ArgumentNullException("lengths"); | |
if (lengths.Length == 0) throw new ArgumentException("Specify at least one length.", "lengths"); | |
if (lengths.Any(v => v < 0)) throw new ArgumentOutOfRangeException("lengths", "The lengths may not be negative."); | |
#endregion | |
// Get the Type of the sub array, e.g. int[][] if there are three lengths specified. | |
Type arrayType = elementType; | |
for (int i = 0; i < lengths.Length - 1; i++) | |
{ | |
arrayType = arrayType.MakeArrayType(); | |
} | |
// Recursively create the sub arrays. | |
return CreateArray(arrayType, defaultValue, lengths[0], lengths.Skip(1).ToArray()); | |
} | |
/// <summary> | |
/// Create an array. | |
/// </summary> | |
/// <param name="elementType">The type of elements in the array.</param> | |
/// <param name="defaultValue">The default value of the most nested elements; | |
/// or <see langword="null"/> to specify none.</param> | |
/// <param name="length">The length of the array.</param> | |
/// <param name="subLengths">The lengths of the arrays nested in the array.</param> | |
/// <returns>The array, with all nested arrays initialzed to their default values.</returns> | |
private static Array CreateArray(Type elementType, object defaultValue, int length, int[] subLengths) | |
{ | |
#region Contract | |
Debug.Assert(elementType != null); | |
Debug.Assert(length >= 0); | |
Debug.Assert(subLengths != null); | |
#endregion | |
// Create the array. | |
Array array = Array.CreateInstance(elementType, length); | |
// If this array has any sub arrays, create them too. | |
if (subLengths.Length > 0) | |
{ | |
for (int i = 0; i < length; i++) | |
{ | |
Array nestedArray = CreateArray(elementType.GetElementType(), defaultValue, subLengths[0], subLengths.Skip(1).ToArray()); | |
array.SetValue(nestedArray, i); | |
} | |
} | |
else if (defaultValue != null) | |
{ | |
for (int i = 0; i < length; i++) | |
{ | |
array.SetValue(defaultValue, i); | |
} | |
} | |
return array; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment