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

.NET反射:确定T数组是否可转换为其他类型,.net,reflection,generics,.net,Reflection,Generics,请注意,这个问题有点微妙,所以请仔细阅读:我不仅仅是想了解某些artibitrary类型是否实现了IEnumerable: interface IRecord : IEnumerable<string> { void OtherMethods(); } 下面是我用初始实现编写的函数: // is "toType" some sort of sequence that would be satisfied // by an array of type T? I

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

interface IRecord : IEnumerable<string>
{
    void OtherMethods();
}
下面是我用初始实现编写的函数:

    // 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;
    }
然后我的脚本解释器需要弄清楚,在这种情况下真正需要的是一个字符串数组

而我希望我的脚本解释器放弃,比如:

void WriteCSV(IRecord record);
尽管IRecord甚至可能实现一些IEnumerable:

interface IRecord : IEnumerable<string>
{
    void OtherMethods();
}
接口IRecord:IEnumerable
{
作废其他方法();
}
我不可能从任何数组构造IRecord


所以我不需要仅仅了解类型实现了什么IEnumerables。我说这很微妙,不是吗?

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

您可以使用这段代码获取特定类型上
IEnumberable
接口的所有实现,然后提取它们的泛型参数

Type type = typeof(ICollection<string>);

IEnumerable<Type> elementTypes = type.GetInterfaces()
    .Where(i => i.IsGenericType 
        && i.GetGenericTypeDefinition() == typeof(IEnumerable<>))
    .Select(i => i.GetGenericArguments()[0]);
Type Type=typeof(ICollection);
IEnumerable elementTypes=type.GetInterfaces()
.Where(i=>i.IsGenericType
&&i.GetGenericTypeDefinition()==typeof(IEnumerable))
.Select(i=>i.GetGenericArguments()[0]);
在本例中,
elementTypes
将是包含
System.String
类型的单个元素


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

根据我在您上一个问题中给出的答案:

您可以使用这段代码获取特定类型上
IEnumberable
接口的所有实现,然后提取它们的泛型参数

Type type = typeof(ICollection<string>);

IEnumerable<Type> elementTypes = type.GetInterfaces()
    .Where(i => i.IsGenericType 
        && i.GetGenericTypeDefinition() == typeof(IEnumerable<>))
    .Select(i => i.GetGenericArguments()[0]);
Type Type=typeof(ICollection);
IEnumerable elementTypes=type.GetInterfaces()
.Where(i=>i.IsGenericType
&&i.GetGenericTypeDefinition()==typeof(IEnumerable))
.Select(i=>i.GetGenericArguments()[0]);
在本例中,
elementTypes
将是包含
System.String
类型的单个元素


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

数组的大小写在
IEnumerable
中,作为一维数组(使用
GetArrayrank
查找的数组)实现IList
IList
,它依次派生自
IEnumerable
。 接下来查找
IEnumerable
并将元素类型视为对象是有意义的——这就是foreach构造处理集合的方式


另一个要考虑的是当提供类型实现代码< >枚举> /COD>几次(例如,<代码> iQueabd和IcEdaby)时的情况。例如, DATACONTROTSCORLALTIZER 在这种情况下不考虑类型作为集合类型。

数组的例子由<代码> iQueDebug < /C> >作为一维数组(您正在使用的代码> GETARAYRANCE )实现<代码> IIST < /Cord>。 接下来查找

IEnumerable
并将元素类型视为对象是有意义的——这就是foreach构造处理集合的方式


另一个要考虑的是当提供类型实现代码< >枚举> /COD>几次(例如,<代码> iQueabd和IcEdaby)时的情况。例如, DATACONTractSerialStase在这种情况下不考虑类型作为集合类型。

< P>可以通过创建泛型参数数组来查看它是否实现了目标类型。示例代码只检查接口,因为确保只实现接口(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>)));
}
private静态类型GetArrayType(类型toType)
{
if(toType.IsArray)
{
if(toType.GetArrayRank()!=1)
返回null;
返回到类型;
}
//验证该类型是否为泛型并且只有一个泛型参数
if(toType.IsGenericType&&toType.GetGenericArguments().Length==1)
{
//创建泛型参数数组,例如IList->int[]
var arrayOfType=toType.GetGenericArguments()[0]。MakeArrayType();
//检查toType是否是数组实现的接口
if(arrayOfType.GetInterfaces()包含(toType))
{
返回arrayOfType//arrayOfType.GetGenericArguments()[0];
}
}    
返回null;
}
公共静态无效测试()
{
AreEqual(typeof(int[]),GetArrayType(typeof(IList));
AreEqual(typeof(int[])、GetArrayType(typeof(ICollection));
AreEqual(typeof(int[])、GetArrayType(typeof(IEnumerable));
IsNull(GetArrayType(typeof(List));
IsNull(GetArrayType(typeof(Dictionary));
}

我希望它能有所帮助。

可以通过创建泛型参数数组来完成,并查看它是否实现了目标类型。示例代码只检查接口,因为确保只实现接口(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>)));
}
private静态类型GetArrayType(类型toType)
{
if(toType.IsArray)
{
if(toType.GetArrayRank()!=1)
返回null;
返回到类型;
}
//验证该类型是否为泛型并且只有一个泛型参数
if(toType.IsGenericType&&toType.GetGenericArguments().Length==1)
{
//创建泛型参数的数组,