我想确定通用对象类型(“T”)方法类型参数是否是集合类型。我通常会将T through作为Generic.List发送,但它可以是任何集合类型,因为它在辅助函数中使用。
我是否最好测试它是否实现IEnumerable< T>?
如果是这样,代码会是什么样的?
更新14:17 GMT + 10可能延伸到解决方案here(但是,如果列表派生的话,它只适用于List&lt; T&gt;不适用于IEnumerable&lt; T&gt;)< /强>
T currentObj;
// works if currentObj is List<T>
currentObj.GetType().GetGenericTypeDefinition() == typeof(List<>)
// does not work if currentObj is List<T>
currentObj.GetType().GetGenericTypeDefinition() == typeof(IEnumerable<>)
答案 0 :(得分:31)
这将是最简单的检查..
if(Obj is ICollection)
{
//Derived from ICollection
}
else
{
//Not Derived from ICollection
}
答案 1 :(得分:15)
你可以使用带有错位名称的Type.GetInterface()。
private bool IsTAnEnumerable<T>(T x)
{
return null != typeof(T).GetInterface("IEnumerable`1");
}
答案 2 :(得分:8)
为了在运行时获取T的实际类型,可以使用typeof(T)表达式。从那里,普通类型比较运算符将起到作用
bool isEnumerable = typeof(IEnumerable<int>).IsAssignableFrom(typeof(T));
完整代码示例:
static bool Foo<T>()
{
return typeof(IEnumerable<int>).IsAssignableFrom(typeof(T));
}
Foo<List<T>>(); // true
Foo<int>(); // false
答案 3 :(得分:7)
我个人倾向于使用自己编写的方法,名为TryGetInterfaceGenericParameters
,我在下面发布。以下是如何在您的情况下使用它:
object currentObj = ...; // get the object
Type[] typeArguments;
if (currentObj.GetType().TryGetInterfaceGenericParameters(typeof(IEnumerable<>), out typeArguments))
{
var innerType = typeArguments[0];
// currentObj implements IEnumerable<innerType>
}
else
{
// The type does not implement IEnumerable<T> for any T
}
这里需要注意的是,您传递了typeof(IEnumerable<>)
,不是 typeof(IEnumerable)
(这是一种完全不同的类型)以及不任何typeof(IEnumerable<T>)
T
(如果您已经知道T
,则不需要此方法)。当然,这适用于任何通用接口,例如您也可以使用typeof(IDictionary<,>)
(但不 typeof(IDictionary)
)。
/// <summary>
/// Determines whether the current type is or implements the specified generic interface, and determines that
/// interface's generic type parameters.</summary>
/// <param name="type">
/// The current type.</param>
/// <param name="interface">
/// A generic type definition for an interface, e.g. typeof(ICollection<>) or typeof(IDictionary<,>).</param>
/// <param name="typeParameters">
/// Will receive an array containing the generic type parameters of the interface.</param>
/// <returns>
/// True if the current type is or implements the specified generic interface.</returns>
public static bool TryGetInterfaceGenericParameters(this Type type, Type @interface, out Type[] typeParameters)
{
typeParameters = null;
if (type.IsGenericType && type.GetGenericTypeDefinition() == @interface)
{
typeParameters = type.GetGenericArguments();
return true;
}
var implements = type.FindInterfaces((ty, obj) => ty.IsGenericType && ty.GetGenericTypeDefinition() == @interface, null).FirstOrDefault();
if (implements == null)
return false;
typeParameters = implements.GetGenericArguments();
return true;
}
答案 4 :(得分:3)
我会测试IEnumerable
,因为集合类型只能实现IEnumerable
,所以不必实现IEnumerable<T>
。
这还取决于:集合类型是什么意思?您可以拥有一个集合,而无需实现任何这些接口。
答案 5 :(得分:3)
另外,请记住,因为您使用的是泛型,不要忘记其他基本技术,在这种情况下,就像重载一样。我怀疑你正在计划这样的事情:
void SomeFunc<T>(T t)
{
if (IsCollectionCase(t))
DoSomethingForCollections()
else
DoSOmethingElse();
}
这样可以更好地处理:
void SomeFunc(IEnumerable t)
{
DoSomethingForCollections()
}
void SomeFunc<T>(T t)
{
DoSomethingElse()
}
答案 6 :(得分:2)
虽然我不能确定原始海报的意图是什么,但是对于IEnumerable进行测试的铸造效果有几个回应。这很好,但是每个人都应该知道字符串实例通过了这个测试,这可能不是原作者想要的。我知道当我去寻找答案时我当然没有找到这篇文章:
string testString = "Test";
Console.WriteLine(testString as IEnumerable != null); // returns true
我正在尝试编写一个使用反射来完成某些任务的自定义序列化程序。作为任务的一部分,我需要确定属性值是项的集合/数组/列表还是单个属性值。特别令人讨厌的是,几个Linq表达式实际上导致了一个可枚举的类型值,但GetType()。IsArray为这些返回false,并将它们转换为ICollection也返回null,但是将它们转换为IEnumerable会返回一个非null值。
所以......目前,我仍然在寻求一种适用于所有情况的解决方案。
答案 7 :(得分:1)
为了简单和代码共享,我通常使用这种扩展方法:
public static bool IsGenericList(this object obj)
{
return IsGenericList(obj.GetType());
}
public static bool IsGenericList(this Type type)
{
if (type == null)
{
throw new ArgumentNullException("type");
}
foreach (Type @interface in type.GetInterfaces())
{
if (@interface.IsGenericType)
{
if (@interface.GetGenericTypeDefinition() == typeof(ICollection<>))
{
// if needed, you can also return the type used as generic argument
return true;
}
}
}
return (type.GetInterface("IEnumerable") != null);
}
答案 8 :(得分:0)
我喜欢仿制药。在此方法中,T
必须具有公共和无参数构造函数,这意味着您无法将IList<object>
用于T
。您必须使用List<object>
public static T IsEnumerable<T>() where T : new() {
if (new T() is IEnumerable) {
}
答案 9 :(得分:0)
我在尝试将任何对象序列化为JSON格式时遇到了同样的问题。以下是我最终使用的内容:
Type typ = value.GetType();
// Check for array type
if(typeof(IEnumerable).IsAssignableFrom(typ) || typeof(IEnumerable<>).IsAssignableFrom(typ))
{
List<object> list = ((IEnumerable)value).Cast<object>().ToList();
//Serialize as an array with each item in the list...
}
else
{
//Serialize as object or value type...
}
答案 10 :(得分:0)
如果您想进行检查并获得所有列表/集合/ IEnumerable的true,但要获取字符串类型的false,则
private static bool IsIEnumerable(Type requestType)
{
var isIEnumerable = typeof(IEnumerable).IsAssignableFrom(requestType);
var notString = !typeof(string).IsAssignableFrom(requestType);
return isIEnumerable && notString;
}