代码之家  ›  专栏  ›  技术社区  ›  Paul Hollingsworth

.NET反射:确定T数组是否可转换为其他类型

  •  1
  • Paul Hollingsworth  · 技术社区  · 16 年前

    注意,这个问题有点微妙,所以请仔细阅读:我不只是想了解一些艺术类型是否实现IEnumerable:

    以下是我用初始实现编写的函数:

        // is "toType" some sort of sequence that would be satisfied
        // by an array of type T? If so, what is the type of T?
        // e.g.
        // getArrayType(typeof(string[]) == typeof(string)
        // getArrayType(typeof(IEnumerable<int>)) == typeof(int)
        // getArrayType(typeof(List<string>)) == null // NOTE - Array<string> does not convert to List<string>
        // etc.
        private static Type getArrayType(Type toType)
        {
            if (toType.IsArray)
            {
                if (toType.GetArrayRank() != 1)
                    return null;
                return toType.GetElementType();
            }
            // Look for IEnumerable<T>, and if so, return the type of T
            if (toType.IsGenericType && toType.GetGenericTypeDefinition() == typeof(IEnumerable<>))
                return toType.GetGenericArguments()[0];
    
            return null;
        }
    

    它能更好地处理更多的案件吗?例如目前

    getType(typeof(ICollection<string>)) == null 
    

    但字符串[]可转换为ICollection

    另外,我不知道“element”类型是什么。

    上下文是:我正在编写一个到脚本语言的反射绑定,如果您将一个对象[]传递给某个期望IEnumerable的方法(在本例中,它将把输入数组的每个元素都转换为一个字符串),我希望它“只起作用”。

    为了澄清,假设我有一些方法签名:

    void WriteCSV(ICollection<string> fields);
    

    我的脚本解释器有一个对象数组,这些对象恰好可以转换为字符串:

    object[] fields = new object[] { "one", 2, "three" };
    

    然后,我的脚本解释器需要弄清楚,在这种情况下真正需要的是字符串数组。

    但是我希望我的脚本解释器放弃,说:

    void WriteCSV(IRecord record);
    

    尽管 iRecord甚至可以实现一些IEnumerable:

    interface IRecord : IEnumerable<string>
    {
        void OtherMethods();
    }
    

    我不可能从任何东西的数组中构造一条IRecord。

    因此,仅仅找出类型实现的IEnumerables并不是我需要的。我 很微妙,不是吗?

    3 回复  |  直到 16 年前
        1
  •  1
  •   Elisha    16 年前

    它可以通过创建一个泛型参数数组来完成,并查看它是否实现了目标类型。示例代码仅检查接口,因为 array 确保仅实现接口(IList、ICollection、IEnumerable)。另外,我从示例返回了数组的类型(只是为了清楚起见),在代码中,您将希望像在发布的示例代码中那样返回泛型参数。

    private static Type GetArrayType(Type toType)
    {
        if (toType.IsArray)
        {
            if (toType.GetArrayRank() != 1)
                return null;
            return toType;
        }
    
        // Verifies the type is generic and has only one generic argument
        if (toType.IsGenericType && toType.GetGenericArguments().Length == 1)
        {
            // Creates an array of the generic argument, e.g. IList<int> -> int[]
            var arrayOfType = toType.GetGenericArguments()[0].MakeArrayType();
    
            // Checks if the toType is an interface that the array implements
            if (arrayOfType.GetInterfaces().Contains(toType))
            {
                return arrayOfType    // arrayOfType.GetGenericArguments()[0];
            }
        }    
        return null;
    }
    
    public static void Test()
    {
        Assert.AreEqual(typeof(int[]), GetArrayType(typeof(IList<int>)));
        Assert.AreEqual(typeof(int[]), GetArrayType(typeof(ICollection<int>)));
        Assert.AreEqual(typeof(int[]), GetArrayType(typeof(IEnumerable<int>)));
    
        Assert.IsNull(GetArrayType(typeof(List<int>)));
        Assert.IsNull(GetArrayType(typeof(Dictionary<int, string>)));
    }
    

    希望能有所帮助。

        2
  •  0
  •   Paul Turner    16 年前

    根据我在你上一个问题中的回答:

    您可以使用这段代码获取 IEnumberable<T> 接口,然后提取它们的泛型参数。

    Type type = typeof(ICollection<string>);
    
    IEnumerable<Type> elementTypes = type.GetInterfaces()
        .Where(i => i.IsGenericType 
            && i.GetGenericTypeDefinition() == typeof(IEnumerable<>))
        .Select(i => i.GetGenericArguments()[0]);
    

    在这个例子中, elementTypes 将是包含的类型的单个元素 System.String .

    如何处理元素类型取决于您自己。因为一个接口可以实现多次,所以您可能希望修改查询以获得单个实现。

        3
  •  0
  •   Dzmitry Huba    16 年前

    数组大小写由 IEnumerable<T> 作为一维数组(您要使用的 GetArrayrank 实施 IList<T> 它反过来又衍生自 IEnumerable<t> . 寻找是有意义的 IEnumerable 接下来,将元素类型视为对象-这是foreach构造处理集合的方式。

    另外一个需要考虑的问题是,当提供的类型实现 IEnumerable<t> 几次(例如, IEnumerable<object> IEnumerable<string> )例如, DataContractSerializer 在本例中,不将该类型视为集合类型。

    推荐文章