Как я могу использовать отражение для поиска свойств, реализующих определенный интерфейс?
Рассмотрим следующий пример:
public interface IAnimal
{
}
public class Cat: IAnimal
{
}
public class DoStuff
{
private Object catList = new List<Cat>();
public void Go()
{
// I want to do this, but using reflection instead:
if (catList is IEnumerable<IAnimal>)
MessageBox.Show("animal list found");
// now to try and do the above using reflection...
PropertyInfo[] properties = this.GetType().GetProperties();
foreach (PropertyInfo property in properties)
{
//... what do I do here?
// if (*something*)
MessageBox.Show("animal list found");
}
}
}
Можете ли вы завершить оператор if, заменив что-то правильным кодом?
EDIT:
Я заметил, что я должен был использовать свойство вместо поля, чтобы это работало, поэтому оно должно быть:
public Object catList
{
get
{
return new List<Cat>();
}
}
Ответы
Ответ 1
Вы можете посмотреть свойства 'PropertyType
, а затем использовать IsAssignableFrom
, который я предполагаю, это то, что вы хотите:
PropertyInfo[] properties = this.GetType().GetProperties();
foreach (PropertyInfo property in properties)
{
if (typeof(IEnumerable<IAnimal>).IsAssignableFrom(property.PropertyType))
{
// Found a property that is an IEnumerable<IAnimal>
}
}
Конечно, вам нужно добавить свойство в свой класс, если вы хотите, чтобы приведенный выше код работал; -)
Ответ 2
Обратите внимание, что в вашем примере catList не будет найден с помощью GetType().GetProperties ()
. Вместо этого вы использовали бы GetType().GetFields ()
.
Если вы пытаетесь определить, определено ли свойство как IEnumerable, вы можете сделать это:
if (typeof(IEnumerable<IAnimal>) == property.PropertyType)
{
MessageBox.Show("animal list found");
}
Если вы хотите узнать, можете ли вы присвоить значение свойства в IEnumerable<IAnimal>
, выполните следующее:
if (typeof(IEnumerable<IAnimal>).IsAssignableFrom (property.PropertyType))
{
MessageBox.Show("animal list found");
}
Если тип свойства недостаточно специфичен (например, object Animal{get;set;}
), чтобы получить ответ, вам нужно будет принять значение. Вы можете сделать это:
object value = property.GetValue(this, null);
if (value is IEnumerable<IAnimal>)
{
MessageBox.Show("animal list found");
}
Ответ 3
Другой способ сделать это - просто вызвать GetProperties()
на интерфейс изнутри объекта, противоположный самому объекту.
public static void DisplayObjectInterface(object source, Type InterfaceName)
{
// Get the interface we are interested in
var Interface = source.GetType().GetInterface(InterfaceName.Name);
if (Interface != null)
{
// Get the properties from the interface, instead of our source.
var propertyList = Interface.GetProperties();
foreach (var property in propertyList)
Debug.Log(InterfaceName.Name + " : " + property.Name + "Value " + property.GetValue(source, null));
}
else
Debug.Log("Warning: Interface does not belong to object.");
}
Мне нравится делать InterfaceName
параметр a Type
, чтобы избежать ошибок при печати GetInterface()
по имени строки.
Использование:
DisplayObjectInterface(Obj, typeof(InterFaceNameGoesHere));
РЕДАКТИРОВАТЬ: я только заметил, что ваш пример представляет собой коллекцию, это не будет работать с коллекцией, переданной в целом. Вам нужно будет передать каждый элемент по отдельности. У меня возникает соблазн удалить, но это, вероятно, поможет другим, что google тот же вопрос ищет решение, которое не является коллекцией.