.NET反射:确定T数组是否可转换为其他类型
请注意,这个问题有点微妙,所以请仔细阅读:我不仅仅是想了解某些artibitrary类型是否实现了IEnumerable:.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
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
查找的数组)实现IListIList
,它依次派生自IEnumerable
。
接下来查找IEnumerable
并将元素类型视为对象是有意义的——这就是foreach构造处理集合的方式
另一个要考虑的是当提供类型实现代码< >枚举> /COD>几次(例如,<代码> iQueabd和
数组的例子由<代码> iQueDebug < /C> >作为一维数组(您正在使用的代码> GETARAYRANCE )实现<代码> IIST < /Cord>。 接下来查找
IEnumerable
并将元素类型视为对象是有意义的——这就是foreach构造处理集合的方式
另一个要考虑的是当提供类型实现代码< >枚举> /COD>几次(例如,<代码> iQueabd和
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)
{
//创建泛型参数的数组,