C# 确定对象是否从集合类型派生
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/750039/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Determine if object derives from collection type
提问by GONeale
I want to determine if a generic object type ("T") method type parameter is a collection type. I would typically be sending T through as a Generic.List but it could be any collection type as this is used in a helper function.
我想确定通用对象类型(“T”)方法类型参数是否是集合类型。我通常会将 T 作为 Generic.List 发送,但它可以是任何集合类型,因为它在辅助函数中使用。
Would I be best to test if it implements IEnumerable<T>?
我最好测试它是否实现了 IEnumerable<T>?
If so, what would the code look like?
如果是这样,代码会是什么样子?
Update 14:17 GMT+10 Possibly extending on a solution here(however only works for List<T>'s not IEnumerable<T>'s when it should if List derives ?)
更新 14:17 GMT+10 可能在此处扩展解决方案(但是仅适用于 List<T>'s not IEnumerable<T>'s when it should if List 派生?)
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<>)
采纳答案by this. __curious_geek
This will be the simplest check..
这将是最简单的检查。
if(Obj is ICollection)
{
//Derived from ICollection
}
else
{
//Not Derived from ICollection
}
回答by J.W.
I would test IEnumerable
instead, since a collection type could implement only IEnumerable
, it doesn't have to implement IEnumerable<T>
.
我会进行测试IEnumerable
,因为集合类型只能实现IEnumerable
,它不必实现IEnumerable<T>
。
It also depends: what do you mean with collection type? You could have a collection without implementing any of those interfaces.
这还取决于:您对集合类型是什么意思?您可以在不实现任何这些接口的情况下拥有一个集合。
回答by Jonathan Rupp
You can use Type.GetInterface() with the mangled name.
您可以将 Type.GetInterface() 与损坏的名称一起使用。
private bool IsTAnEnumerable<T>(T x)
{
return null != typeof(T).GetInterface("IEnumerable`1");
}
回答by JaredPar
In order to get the actual type of T at runtime, you can use the typeof(T) expression. From there the normal type comparison operators will do the trick
为了在运行时获得 T 的实际类型,您可以使用 typeof(T) 表达式。从那里开始,普通的类型比较运算符会起作用
bool isEnumerable = typeof(IEnumerable<int>).IsAssignableFrom(typeof(T));
Full Code Sample:
完整代码示例:
static bool Foo<T>()
{
return typeof(IEnumerable<int>).IsAssignableFrom(typeof(T));
}
Foo<List<T>>(); // true
Foo<int>(); // false
回答by James Curran
Also, remember just because you are using generics, don't forget other basic techniques, in this case, like overloading. I suspect the you are planning something like this:
另外,请记住,仅仅因为您使用的是泛型,不要忘记其他基本技术,在这种情况下,例如重载。我怀疑你正在计划这样的事情:
void SomeFunc<T>(T t)
{
if (IsCollectionCase(t))
DoSomethingForCollections()
else
DoSOmethingElse();
}
This would be far better handled as:
这会更好地处理为:
void SomeFunc(IEnumerable t)
{
DoSomethingForCollections()
}
void SomeFunc<T>(T t)
{
DoSomethingElse()
}
回答by Mitselplik
While I can't be certain what the original poster's intent was, there have been several responses to the effect of casting to IEnumerable for testing. That's fine, but everyone should be aware that string instances pass this test, which may not be something the original author intended. I know I certainly didn't when I went looking for an answer and found this post:
虽然我不能确定最初发布者的意图是什么,但对转换到 IEnumerable 进行测试的效果有几种回应。这很好,但每个人都应该知道字符串实例通过了这个测试,这可能不是原作者想要的。我知道当我去寻找答案并找到这篇文章时,我当然没有:
string testString = "Test";
Console.WriteLine(testString as IEnumerable != null); // returns true
I am in the process of trying to write a custom serializer that uses reflection to accomplish certain tasks. As part of a task, I need to determine if a property value is a collection/array/list of items or a single property value. What is particularly annoying is that several Linq expressions actually result in an enumerable type value, but GetType().IsArray returns false for these, and casting them to ICollection returns null as well, but casting them to IEnumerable returns a non-null value.
我正在尝试编写一个使用反射来完成某些任务的自定义序列化程序。作为任务的一部分,我需要确定属性值是集合/数组/项目列表还是单个属性值。特别令人讨厌的是,几个 Linq 表达式实际上会产生一个可枚举类型的值,但 GetType().IsArray 为这些返回 false,将它们转换为 ICollection 也返回 null,但将它们转换为 IEnumerable 返回非空值。
So...for the time being, I am still seeking a solution that works for all cases.
所以……目前,我仍在寻找适用于所有情况的解决方案。
回答by Timwi
Personally I tend to use a method that I wrote myself, called TryGetInterfaceGenericParameters
, which I posted below. Here is how to use it in your case:
就我个人而言,我倾向于使用我自己编写的一种方法,称为TryGetInterfaceGenericParameters
,我在下面发布了它。以下是如何在您的情况下使用它:
Example of use
使用示例
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
}
It is important to note here that you pass in typeof(IEnumerable<>)
, nottypeof(IEnumerable)
(which is an entirely different type) and also nottypeof(IEnumerable<T>)
for any T
(if you already know the T
, you don't need this method). Of course this works with any generic interface, e.g. you can use typeof(IDictionary<,>)
as well (but nottypeof(IDictionary)
).
重要的是要注意,您传入typeof(IEnumerable<>)
, nottypeof(IEnumerable)
(这是一种完全不同的类型)并且也不typeof(IEnumerable<T>)
是 any T
(如果您已经知道T
,则不需要此方法)。当然,这适用于任何通用接口,例如您也可以使用typeof(IDictionary<,>)
(但不是typeof(IDictionary)
)。
Method source
方法来源
/// <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;
}
回答by guneysus
I love generics. In this method T
must have a public and parameterless constructor which means you can not use IList<object>
for T
. You must use List<object>
我喜欢泛型。在这个方法中T
必须有一个公共和无参数的构造函数,这意味着你不能使用IList<object>
for T
。你必须使用List<object>
public static T IsEnumerable<T>() where T : new() {
if (new T() is IEnumerable) {
}
回答by k rey
I came across the same issue while attempting to serialize any object to JSON format. Here is what I ended up using:
我在尝试将任何对象序列化为 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...
}
回答by Chipo Hamayobe
For simplicity and code sharing, I usually use this extension method:
为了简单和代码共享,我通常使用这种扩展方法:
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);
}