[英]How to find out if an object's type implements IEnumerable<X> where X derives from Base using Reflection
Give a base class Base
, I want to write a method Test, like this: 给一个基类Base
,我想写一个方法Test,像这样:
private static bool Test(IEnumerable enumerable)
{
...
}
such that Test returns true if the type of o implements any interface of IEnumerable<X>
where X
derives from Base
, so that if I would do this: 如果o的类型实现了IEnumerable<X>
任何接口,其中X
派生自Base
,那么Test返回true,所以如果我这样做:
public static IEnumerable<string> Convert(IEnumerable enumerable)
{
if (Test(enumerable))
{
return enumerable.Cast<Base>().Select(b => b.SomePropertyThatIsString);
}
return enumerable.Cast<object>().Select(o => o.ToString());
}
...that it would do the right thing, using Reflection. ......使用Reflection,它会做正确的事情。 I'm sure that its a matter of walking across all the interfaces of the type to find the first that matches the requirements, but I'm having a hard time finding the generic IEnumerable<>
among them. 我确信这是跨越所有类型接口的问题,找到符合要求的第一个,但我很难找到其中的通用IEnumerable<>
。
Of course, I could consider this: 当然,我可以考虑一下:
public static IEnumerable<string> Convert(IEnumerable enumerable)
{
return enumerable.Cast<object>().Select(o => o is Base ? ((Base)o).SomePropertyThatIsString : o.ToString());
}
...but think of it as a thought experiment. ......但是把它想象成一个思想实验。
You could also use a LINQ query that could look like this. 您还可以使用看起来像这样的LINQ查询。
public static bool ImplementsBaseType(IEnumerable objects)
{
int found = ( from i in objects.GetType().GetInterfaces()
where i.IsGenericType &&
i.GetGenericTypeDefinition() == typeof(IEnumerable<>) &&
typeof(MyBaseClass).IsAssignableFrom(i.GetGenericArguments()[0])
select i ).Count();
return (found > 0);
}
This code assumes the following using statements: 此代码假定以下using语句:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
Since this is just a thought experiment. 因为这只是一个思想实验。 Here is another implementation as an extension method. 这是另一种实现作为扩展方法。
public static class ConversionAssistants
{
public static bool GenericImplementsType(this IEnumerable objects, Type baseType)
{
foreach (Type type in objects.GetType().GetInterfaces())
{
if (type.IsGenericType)
{
if (type.GetGenericTypeDefinition() == typeof(IEnumerable<>))
{
if (baseType.IsAssignableFrom(type.GetGenericArguments()[0]))
return true;
}
}
}
return false;
}
}
You can use the Type.FindInterfaces
to filter out all the IEnumerable<>
interfaces the type implements and check the generic parameters (through Type.GetGenericArguments
) on each of them to see if it's Base
or inherits from Base
. 您可以使用Type.FindInterfaces
过滤掉类型实现的所有IEnumerable<>
接口,并检查每个接口上的泛型参数(通过Type.GetGenericArguments
),以查看它是Base
还是继承自Base
。
Update : Here's some sample code: 更新 :这是一些示例代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
namespace ConsoleApplication1
{
class Base
{
string Prop { get; set;}
}
class A : Base
{
}
class Test : List<A>
{
}
class Program
{
static void Main(string[] args)
{
try
{
Test test = new Test();
Type myType = test.GetType();
//string filterCriteria = "IEnumerable`1";
Type typeA = Type.GetType("ConsoleApplication1.A");
string filterCriteria = "System.Collections.Generic.IEnumerable`1[[" +
typeA.AssemblyQualifiedName +
"]]";
// Specify the TypeFilter delegate that compares the
// interfaces against filter criteria.
TypeFilter myFilter = new TypeFilter(MyInterfaceFilter);
Type[] myInterfaces = myType.FindInterfaces(myFilter,
filterCriteria);
if (myInterfaces.Length > 0)
{
Console.WriteLine("\n{0} implements the interface {1}.",
myType, filterCriteria);
for (int j = 0; j < myInterfaces.Length; j++)
Console.WriteLine("Interfaces supported: {0}.",
myInterfaces[j].ToString());
}
else
Console.WriteLine(
"\n{0} does not implement the interface {1}.",
myType, filterCriteria);
}
catch (ArgumentNullException e)
{
Console.WriteLine("ArgumentNullException: " + e.Message);
}
catch (TargetInvocationException e)
{
Console.WriteLine("TargetInvocationException: " + e.Message);
}
catch (Exception e)
{
Console.WriteLine("Exception: " + e.Message);
}
}
public static bool MyInterfaceFilter(Type typeObj, Object criteriaObj)
{
// This will be true, if criteria is
// System.Collections.Generic.IEnumerable`1[[ConsoleApplication1.A, ConsoleApplication1, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]
if (typeObj.FullName == criteriaObj.ToString())
return true;
// This will be true, if criteria is
// IEnumerable`1
// You will still need to check the generic parameters on the original type
// (generic parameters are not exposed on Type instances for interfaces
else if (typeObj.Name == criteriaObj.ToString())
return true;
else
return false;
}
}
}
I've written some code recently that needs to iterate over any collection. 我最近编写了一些需要迭代任何集合的代码。
As a legacy .NET app, I didn't even have generics available to me! 作为一个传统的.NET应用程序,我甚至没有可用的泛型!
Here's an extract : 这是一个摘录:
var t = objects.GetType(); // to be compatible with the question
bool isIEnumerable = false;
foreach (var i in t.GetInterfaces())
{
if (i == typeof(IEnumerable))
{
isIEnumerable = true;
break;
}
}
I found that even the .NET 1.1 collection classes such as SqlParameterCollection were IEnumerable. 我发现即使是.NET 1.1集合类,如SqlParameterCollection也是IEnumerable。
It also catches generic collections such as List<> as those too are IEnumerable. 它还捕获了像List <>这样的通用集合,因为它们也是IEnumerable。
Hope this helps someone. 希望这有助于某人。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.