.NET反思:确定T的阵列是否可以转换成其他类型 [英] .NET reflection: determining whether an array of T would be convertible to some other type

查看:123
本文介绍了.NET反思:确定T的阵列是否可以转换成其他类型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

请注意,这个问题有点微妙所以请仔细阅读它:我不只是试图找出一些artibitrary类型是否实现IEnumerable

Note, this question is a bit subtle so read it carefully: I'm not just trying to find out whether some artibitrary type implements IEnumerable:

下面是我写的一个初步实现功能:

Here's a function I've written with an initial implementation:

    // 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;
    }

它可以更好,处理更多的案件?例如目前

Can it be better and handle more cases? e.g. currently

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

但字符串[]可转换为ICollection的

but string[] is convertible to ICollection

另请注意,我不知道事先什么元素类型。

Note also, I don't know in advance what the "element" type is.

上下文是:我正在写一个反映绑定到一个脚本语言,我希望它只是工作,如果你传递一个对象[]一些方法期望的IEnumerable(它会互相转换的元素输入数组为字符串,在这种情况下)。

The context is: I'm writing a reflection binding to a scripting language and I want it to "just work" if you pass an object[] to some method that expects IEnumerable (it would convert each of the elements of the input array to a string, in this case).

所以要澄清,说我有一些方法的签名:

So to clarify, say I have some method signature:

void WriteCSV(ICollection<string> fields);

和我的脚本跨preTER有对象的数组,所有恰巧是转换,IBLE字符串:

and my script interpreter has an array of objects that all happen to be Convert-ible to string:

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

然后我的脚本跨preTER需要弄清楚,什么是真正需要在这种情况下是一个字符串数组。

Then my script interpreter needs to figure out that what's really needed in this case is an array of strings.

而我希望我的脚本跨preTER放弃,说:

Whereas I want my script interpreter to give up on, say:

void WriteCSV(IRecord record);

尽管的IRecord甚至可能会执行一些IEnumerable的:

even though IRecord might even implement some IEnumerable:

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

有没有办法,我可以从任何一个数组构造IRecord。

There's no way I can construct an IRecord from an array of anything.

所以只要找出什么IEnumerables一种工具是不是我所需要的。我的的是微妙的,不是吗?

So just finding out what IEnumerables a type implements isn't what I need. I said it was subtle didn't I?

推荐答案

可以通过创建一个通用的参数数组做,看看它是否实现了目标类型。对于接口的例子code盘只因为阵列保证实现接口的唯一(的IList,ICollection的,IEnumerable的)。此外,我从例子中返回数组的类型(只是要清楚),在你们code,你会希望将一般的参数返回作为您发布的样品code。

It can be done by creating an array of the generic argument and see if it implements the target type. The example code checks for interfaces only since array ensures implementing interfaces only (IList, ICollection, IEnumerable). In addition i returned from the example the type of array (just to make it clear), in you code you will want to return the generic argument as in the sample code you posted.

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>)));
}

我希望它能帮助。

I hope it helps.

这篇关于.NET反思:确定T的阵列是否可以转换成其他类型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆