Дайте базовый класс Base
, Я хочу записать Тест метода, как это:
private static bool Test(IEnumerable enumerable)
{
...
}
таким образом, что Тест возвращает true, если тип o реализует какой-либо интерфейс IEnumerable<X>
где X
происходит из Base
, так, чтобы, если я сделал бы это:
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());
}
... то, что это сделало бы правильную вещь, с помощью Отражения. Я уверен, что это - вопрос обхода через все интерфейсы типа для нахождения первого, которое соответствует требованиям, но мне нелегко находить дженерик IEnumerable<>
среди них.
Конечно, я мог рассмотреть это:
public static IEnumerable<string> Convert(IEnumerable enumerable)
{
return enumerable.Cast<object>().Select(o => o is Base ? ((Base)o).SomePropertyThatIsString : o.ToString());
}
... но думайте о нем как о мысленном эксперименте.
Вы также можете использовать запрос 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);
}
Этот код предполагает следующие операторы using:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
Поскольку это всего лишь мысленный эксперимент. Вот еще одна реализация в качестве метода расширения.
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;
}
}
Вы можете использовать Type.FindInterfaces
, чтобы отфильтровать все IEnumerable <>
интерфейсы, которые тип реализует и проверьте общие параметры (через Type.GetGenericArguments
) для каждого из них, чтобы узнать, является ли он Base
или наследуется от Base
.
Обновление : Вот пример кода:
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;
}
}
}