我有一个方法需要一个通用参数T.在内部,要决定调用什么其他方法,我需要知道(不限制它)如果该参数是一个List或只是一些东西。我的泛型是一个列表,还是一个项目?
我该怎么做?
我一直在使用
var isList = typeof(T).Name.ToLower().Contains("list`1");
但感觉就像一个肮脏的方法。什么更清洁?
我有一个方法需要一个通用参数T.在内部,要决定调用什么其他方法,我需要知道(不限制它)如果该参数是一个List或只是一些东西。我的泛型是一个列表,还是一个项目?
我该怎么做?
我一直在使用
var isList = typeof(T).Name.ToLower().Contains("list`1");
但感觉就像一个肮脏的方法。什么更清洁?
var type = typeof(T);
bool isList = type.IsGenericType && type.GetGenericTypeDefinition() == typeof(List<>);
如果您不需要为列表精确匹配,也可能只是检查是否typeof(IList).IsAssignableFrom(typeof(T))
,其中有许多类似列表的集合实现。
如果你想支持T等于IList<T2>
直接(所以类型参数T是一个接口),那么你需要检查该分开(GetGenericTypeDefinition()
也可以返回typeof(IList<>)
)。
如果您想要支持从任何IList<>
继承的任何类型T,那么您必须获得更多的创造性。您必须枚举所有接口,检查它们是否是通用的(如上所述),然后检查接口的通用类型是否为IList<>
。此外,由于Type上的GetInterfaces()调用仅返回顶层接口,因此您需要遍历每个接口实现的所有接口(递归),以便检查这些接口。丑,我知道。
那么,你总是可以使用typeof(T)
和is
关键字,但我会再看看你的设计。
你的方法实际上是击败了通用方法的目的。如果您必须检查泛型参数的类型,那么您的方法不是通用的。泛型非常适合您不关心底层类型的场景。如果你在乎,那么该方法不应该是通用的,它应该被重载(可能)。如何告诉我们你在这里实际想要完成什么,以便我们能够给予更多有用的回应?
你真的不想知道。 :)我创建一个基本查询对象通过调用NHibernate的ISqlQuery.List()或ISqlQuery.UniqueResult的方法 - 返回存储过程的结果作为动态类型。而不是采取预先“知道”,并要求调用代码调用“单”或“名单”的方法,我想通过在后端这一决定,以帮助开发者的。 – reallyJim
@reallyJim:有点像[Massive](https://github.com/robconery/massive)? –
@jim Schubert是的 - 没有意识到我正在接近重新发明轮子。问题的根源在于我必须处理返回需要转换为业务对象的结果的SPROC,但我不想为其创建映射。 – reallyJim
如果您正在寻找任何内置集合,您将检查IEnumerable。这样你就不用担心类型参数。但是这会带来问题,因为字符串实现了IEnumerable。因此,你需要像这样的代码:
if (typeof(T) is string) {
} else if (typeof(T) is IEnumerable) {
} else { // its something else
}
根据对列表的含义的理解,“IEnumerable”可能涵盖太多东西。例如,与“IList”不同,“IEnumerable”本身是只读的:我可以例如实现一个返回斐波那契数列的IEnumerable类。你会认为这个类的一个实例是一个列表吗? – stakx
@stakx - 好点,我更新了我的答案。 –
你尝试比较它与另一个列表的对象类型? – krs1
如果您将其传递给'NotReallyAList'实例,则会失败。 –
什么*确切*你是什么意思,当你说“名单”?你的意思是确切的类型'System.Collections.Generic.List'?或者你的意思是什么0或更多的项目?或者可以读取以及更新的任何类型的集合? –
stakx