我创建了一个方法来告诉我通用IEnumerable中对象的类型是什么。 这似乎是一个简单的事情,但当我尝试将值集合从Dictionary传递给我的方法时,我得到了意想不到的结果。 我想知道如何修复方法以返回正确的结果,理想情况下我还想解释为什么我得到了我得到的结果。
//sample class (target type to get)
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
}
//method that extracts the type
public Type GetItemType(IEnumerable<object> collection)
{
Type collectionType = collection.GetType();
Type[] genericArguments = collectionType.GetGenericArguments();
return genericArguments[0];
}
//sample data for test
var folk = new Dictionary<string, Person>();
folk.Add("Joe", new Person() { Name="Joseph Stalin", Age = 43 });
folk.Add("Tony", new Person() { Name="Winston Churchill", Age = 65 });
IEnumerable<Person> people = folk.Values;
Type itemType = GetItemType(people);
itemType是&#34; System.String&#34;而不是&#34;人&#34;。 它似乎从实际的Dictionary中获取类型泛型参数,而不是值集合。
答案 0 :(得分:1)
您遇到的问题是IEnumerable<object>
背后有一个基础类型,而您的案例中的类型是Dictionary<string, Person>.ValueCollection
。
如果您使用调试器并检查collectionType
,则可以看到。要解决此问题,您可以在初始化.ToList()
时添加people
,将集合转换为列表:
IEnumerable<Person> people = folk.Values.ToList();
现在IEnumerable<object>
背后的类型为List<Person>
,应该会为您提供所需的结果。
另一种“修复”方法是将您的方法签名更改为:
public Type GetItemType<T>(IEnumerable<T> collection)
即使没有将Values集合转换为列表,也会返回Person
类型。
答案 1 :(得分:1)
这里的问题实际上是一个微妙的问题。发生了什么folk.Values
的实际运行时类型是Dictionary
的嵌套类。具体来说,它是Dictionary<string, Person>.ValueCollection
。实际上,通用参数会移至ValueCollection
类型,第一个参数最终为string
。
理想情况下,您真正需要做的就是更改方法签名:
public Type GetItemType<T>( IEnumerable<T> collection )
{
return typeof( T );
}
要在不引入实际通用参数的情况下解决这个问题,您需要执行以下操作:
public Type GetItemType(IEnumerable<object> collection)
{
Type collectionType = collection.GetType();
collectionType.Dump();
return collectionType.GetInterfaces()
.Where( iface => iface.IsGenericType )
.Where( iface => iface.GetGenericTypeDefinition() == typeof( IEnumerable<> ) )
.Select( iface => iface.GetGenericArguments()[0] ).FirstOrDefault();
}
在这种情况下,我们枚举集合类型实现的接口寻找IEnumerable<>
,然后拉出它的泛型参数。请注意,如果您发现使用不同泛型参数类型多次实现IEnumerable<>
的类型,则会遇到问题。
答案 2 :(得分:0)
您的GetItemType
方法获得了IEnumerable<object>
。是否保证IEnumerable中的所有项目都是相同的类型?
如果没有,则需要返回IEnumerable类型。
如果是,您只需要查看第一个,然后返回collection.First().GetType()
这是你在找什么?
哦,实际上,请查看@ itsme86评论,这是一种更干净的方式来做你想做的事情