如何确定 rank 1 数组是向量还是多维数组?

Posted

技术标签:

【中文标题】如何确定 rank 1 数组是向量还是多维数组?【英文标题】:How to determine if rank 1 array is a vector or multidimensional array? 【发布时间】:2020-07-06 15:34:03 【问题描述】:

给定一个数组类型 (type.IsArray == true),如何确定 rank 1 数组 (type.GetArrayRank() == 1) 是向量数组还是多维数组?

var vectorArrayType = typeof(string).MakeArrayType();

var multiDimensionalArrayType = typeof(string).MakeArrayType(1);

有什么比在type.Name 中查找[][*] 更好的方法吗?

【问题讨论】:

@AlexeiLevenkov MakeArrayType "注意公共语言运行时区分向量(即始终从零开始的一维数组)和多维数组。总是只有一维,和多维数组碰巧只有一维是不一样的。这种方法重载只能用于创建向量类型,是创建向量类型的唯一方法。使用 MakeArrayType( Int32) 方法重载以创建多维数组类型。" @MichaelRandall wow... 显然我看不懂 :) 谢谢... 因为它看起来像 MakeArrayType 返回缓存类型,所以有一种方法可以比较 typeof(string).MakeArrayType() == typeof(string).MakeArrayType(1) (false) - 也许它是 OP 正在寻找的方式吗? @jwdonahue - 我在那个链接中看不到任何有用的东西。 这是XY problem吗?你想区分数组类型和向量类型吗?还是一维与多维数组? @AlexeiLevenkov - 我测试了它并且它有效。 【参考方案1】:

解决方案

public enum ArrayKind

    /// <summary>
    /// Not an array.
    /// </summary>
    None,

    /// <summary>
    /// A vector array.  Can only have a single dimension.
    /// </summary>
    Vector,

    /// <summary>
    /// A multidimensional array.  Can have 1 to 32 dimensions.
    /// </summary>
    MultiDimensional,


public static class TypeExtensions

    /// <summary>
    /// Determines the kind of array that the specified type is.
    /// </summary>
    /// <param name="type">The type.</param>
    /// <returns>
    /// The kind of array of the specified type.
    /// </returns>
    /// <exception cref="ArgumentNullException"><paramref name="type"/> is null.</exception>
    public static ArrayKind GetArrayKind(
        this Type type)
    
        if (type == null)
        
            throw new ArgumentNullException(nameof(type));
        

        ArrayKind result;

        if (!type.IsArray)
        
            result = ArrayKind.None;
        
        else if (type.GetArrayRank() > 1)
        
            result = ArrayKind.MultiDimensional;
        
        else if (type == type.GetElementType().MakeArrayType())
        
            result = ArrayKind.Vector;
        
        else
        
            result = ArrayKind.MultiDimensional;
        

        return result;
    

测试

需要 xUnit 和 FluentAssertions

    [Fact]
    public static void GetArrayKind___Should_throw_ArgumentNullException___When_parameter_type_is_null()
    
        // Arrange, Act
        var actual = Record.Exception(() => TypeExtensions.GetArrayKind(null));

        // Assert
        actual.Should().BeOfType<ArgumentNullException>();
        actual.Message.Should().Contain("type");
    

    [Fact]
    public static void GetArrayKind___Should_return_ArrayKind_None___When_type_is_not_an_array()
    
        // Arrange
        var types = new[]
        
            typeof(object),
            typeof(string),
            typeof(Guid),
            typeof(DateTime),
            typeof(int),
            typeof(Guid?),
            typeof(DateTime?),
            typeof(int?),
            typeof(IReadOnlyCollection<object>),
            typeof(IReadOnlyCollection<string>),
            typeof(IReadOnlyCollection<Guid>),
            typeof(IReadOnlyCollection<DateTime>),
            typeof(IReadOnlyCollection<int>),
            typeof(List<object>),
            typeof(List<string>),
            typeof(List<Guid>),
            typeof(List<DateTime>),
            typeof(List<int>),
        ;

        // Act
        var actuals = types.Select(_ => _.GetArrayKind()).ToList();

        // Assert
        actuals.Should().AllBeEquivalentTo(ArrayKind.None);
    

    [Fact]
    public static void GetArrayKind___Should_return_ArrayKind_Vector___When_type_is_a_vector_array()
    
        // Arrange
        var types = new[]
        
            typeof(object[]),
            typeof(string[]),
            typeof(Guid[]),
            typeof(DateTime[]),
            typeof(int[]),
            typeof(Guid?[]),
            typeof(DateTime?[]),
            typeof(int?[]),
            typeof(IReadOnlyCollection<object>[]),
            typeof(IReadOnlyCollection<string>[]),
            typeof(IReadOnlyCollection<Guid>[]),
            typeof(IReadOnlyCollection<DateTime>[]),
            typeof(IReadOnlyCollection<int>[]),
            typeof(List<object>[]),
            typeof(List<string>[]),
            typeof(List<Guid>[]),
            typeof(List<DateTime>[]),
            typeof(List<int>[]),
            typeof(object[][]),
            typeof(string[][]),
            typeof(Guid[][]),
            typeof(DateTime[][]),
            typeof(int[][]),
            typeof(Guid?[][]),
            typeof(DateTime?[][]),
            typeof(int?[][]),
            typeof(IReadOnlyCollection<object>[][]),
            typeof(IReadOnlyCollection<string>[][]),
            typeof(IReadOnlyCollection<Guid>[][]),
            typeof(IReadOnlyCollection<DateTime>[][]),
            typeof(IReadOnlyCollection<int>[][]),
            typeof(List<object>[][]),
            typeof(List<string>[][]),
            typeof(List<Guid>[][]),
            typeof(List<DateTime>[][]),
            typeof(List<int>[][]),
            typeof(object[][,]),
            typeof(string[][,]),
            typeof(Guid[][,]),
            typeof(DateTime[][,]),
            typeof(int[][,]),
            typeof(Guid?[][,]),
            typeof(DateTime?[][,]),
            typeof(int?[][,]),
            typeof(IReadOnlyCollection<object>[][,]),
            typeof(IReadOnlyCollection<string>[][,]),
            typeof(IReadOnlyCollection<Guid>[][,]),
            typeof(IReadOnlyCollection<DateTime>[][,]),
            typeof(IReadOnlyCollection<int>[][,]),
            typeof(List<object>[][,]),
            typeof(List<string>[][,]),
            typeof(List<Guid>[][,]),
            typeof(List<DateTime>[][,]),
            typeof(List<int>[][,]),
        ;

        // Act
        var actuals = types.Select(_ => _.GetArrayKind()).ToList();

        // Assert
        actuals.Should().AllBeEquivalentTo(ArrayKind.Vector);
    

    [Fact]
    public static void GetArrayKind___Should_return_ArrayKind_MultiDimensional___When_type_is_a_multidimensional_array()
    
        // Arrange
        var types = new[]
        
            typeof(object[,]),
            typeof(string[,]),
            typeof(Guid[,]),
            typeof(DateTime[,]),
            typeof(int[,]),
            typeof(Guid?[,]),
            typeof(DateTime?[,]),
            typeof(int?[,]),
            typeof(IReadOnlyCollection<object>[,]),
            typeof(IReadOnlyCollection<string>[,]),
            typeof(IReadOnlyCollection<Guid>[,]),
            typeof(IReadOnlyCollection<DateTime>[,]),
            typeof(IReadOnlyCollection<int>[,]),
            typeof(List<object>[,]),
            typeof(List<string>[,]),
            typeof(List<Guid>[,]),
            typeof(List<DateTime>[,]),
            typeof(List<int>[,]),
            typeof(object[,][]),
            typeof(string[,][]),
            typeof(Guid[,][]),
            typeof(DateTime[,][]),
            typeof(int[,][]),
            typeof(Guid?[,][]),
            typeof(DateTime?[,][]),
            typeof(int?[,][]),
            typeof(IReadOnlyCollection<object>[,][]),
            typeof(IReadOnlyCollection<string>[,][]),
            typeof(IReadOnlyCollection<Guid>[,][]),
            typeof(IReadOnlyCollection<DateTime>[,][]),
            typeof(IReadOnlyCollection<int>[,][]),
            typeof(List<object>[,][]),
            typeof(List<string>[,][]),
            typeof(List<Guid>[,][]),
            typeof(List<DateTime>[,][]),
            typeof(List<int>[,][]),
            typeof(object).MakeArrayType(1),
            typeof(string).MakeArrayType(1),
            typeof(Guid).MakeArrayType(1),
            typeof(DateTime).MakeArrayType(1),
            typeof(int).MakeArrayType(1),
            typeof(Guid?).MakeArrayType(1),
            typeof(DateTime?).MakeArrayType(1),
            typeof(int?).MakeArrayType(1),
            typeof(IReadOnlyCollection<object>).MakeArrayType(1),
            typeof(IReadOnlyCollection<string>).MakeArrayType(1),
            typeof(IReadOnlyCollection<Guid>).MakeArrayType(1),
            typeof(IReadOnlyCollection<DateTime>).MakeArrayType(1),
            typeof(IReadOnlyCollection<int>).MakeArrayType(1),
            typeof(List<object>).MakeArrayType(1),
            typeof(List<string>).MakeArrayType(1),
            typeof(List<Guid>).MakeArrayType(1),
            typeof(List<DateTime>).MakeArrayType(1),
            typeof(List<int>).MakeArrayType(1),
            typeof(object[]).MakeArrayType(1),
            typeof(string[]).MakeArrayType(1),
            typeof(Guid[]).MakeArrayType(1),
            typeof(DateTime[]).MakeArrayType(1),
            typeof(int[]).MakeArrayType(1),
            typeof(Guid?[]).MakeArrayType(1),
            typeof(DateTime?[]).MakeArrayType(1),
            typeof(int?[]).MakeArrayType(1),
            typeof(IReadOnlyCollection<object>[]).MakeArrayType(1),
            typeof(IReadOnlyCollection<string>[]).MakeArrayType(1),
            typeof(IReadOnlyCollection<Guid>[]).MakeArrayType(1),
            typeof(IReadOnlyCollection<DateTime>[]).MakeArrayType(1),
            typeof(IReadOnlyCollection<int>[]).MakeArrayType(1),
            typeof(List<object>[]).MakeArrayType(1),
            typeof(List<string>[]).MakeArrayType(1),
            typeof(List<Guid>[]).MakeArrayType(1),
            typeof(List<DateTime>[]).MakeArrayType(1),
            typeof(List<int>[]).MakeArrayType(1),
        ;

        // Act
        var actuals = types.Select(_ => _.GetArrayKind()).ToList();

        // Assert
        actuals.Should().AllBeEquivalentTo(ArrayKind.MultiDimensional);
    

【讨论】:

以上是关于如何确定 rank 1 数组是向量还是多维数组?的主要内容,如果未能解决你的问题,请参考以下文章

将c多维数组转换为多维c++向量

std::vector 和多维数组的连续内存

多维数组

数据库中数据写入多维数组,如何实现?

有啥可以代替多维数组?

php如何判断数组是一维还是多维