#c# #reflection #system.reflection
#c# #отражение #system.reflection
Вопрос:
Я немного боролся с некоторым кодом отражения, который, как я думал, был бы простым. По сути, у меня есть интерфейс, который определяет метод. Затем у меня есть абстрактный класс, который предоставляет базовую реализацию этого метода.
Конкретные классы могут содержать вложенные экземпляры других классов, которые также могут быть производными от того же базового класса. Это можно проиллюстрировать следующим примером:
using System.Linq;
public interface ISampleObject
{
bool IsValid();
}
public abstract class SampleObjectBase : ISampleObject
{
public bool IsValid()
{
var returnValue = true;
// Self-validation sets the return value.
var childProperties = this.GetType().GetProperties().Where(pi => typeof(ISampleObject).IsAssignableFrom(pi.PropertyType));
foreach (var childProperty in childProperties)
{
// var childInstance = ????; // Need the actual *existing* instance property, cast to ISampleObject.
// if (childInstance.IsValid() != true)
// {
// returnValue = false;
// }
}
return returnValue;
}
}
public sealed class InnerSampleObject : SampleObjectBase
{
}
public sealed class OuterSampleObject : SampleObjectBase
{
public InnerSampleObject DerivedSampleObject { get; set; }
}
Моя проблема в том, что в прокомментированном коде для SampleObjectBase я не могу получить конкретный экземпляр соответствующего значения PropertyInfo. Если я посмотрю на объект PropertyInfo в цикле, я увижу, что тип правильный, но я не могу найти способ прямого доступа к экземпляру, который уже существует в реализации. Итак, при выполнении, например, OuterSampleObject.При использовании функции valid() код находит PropertyInfo для InnerSampleObject, как и ожидалось. Я хочу выполнить InnerSampleObject.isValid().
Я пробовал (несколько вариантов):
var childIsValid = (bool)contractProperty.PropertyType.InvokeMember("IsValid", BindingFlags.InvokeMethod, null, null, null);
И:
var childInstance = (ISampleContract)contractProperty;
Проблема с первым из них заключается в том, что я не могу передать null в качестве целевого значения для InvokeMember, поскольку isValid() не является статическим (и не может быть, поскольку я сосредоточен на реальном экземпляре). Второй вариант — это просто неудачное приведение, но это суть того, чего я хочу достичь.
Приведенный выше пример кода — это просто минималистичный пример того, чего я хочу достичь. Полный код является частью самоподтверждающегося DTO, который рекурсивно проверяет всю иерархию и возвращает, какие дочерние элементы имеют проблемы с проверкой и каковы они.
Любая помощь была бы высоко оценена.
Комментарии:
1. Похоже, что вашего
returnValue
никогда не может бытьtrue
.2. Просто опечатка. Исправлено, однако. 😉
Ответ №1:
Как насчет:
var instance = childProperty.GetValue(this, null) as ISampleObject;
if (instance != null)
{
if (!instance.IsValid())
return false;
}
Комментарии:
1. О боже… Я думал, что однажды попробовал это, и получил исключение StackOverflowException. Жаль, что у меня нет старой версии, чтобы увидеть, что я на самом деле сделал, но это работает просто великолепно. 🙂
Ответ №2:
Пожалуйста, посмотрите, соответствует ли приведенный ниже код тому, что вы ищете. Мои изменения отмечены комментарием, начинающимся с //VH:
public interface ISampleObject
{
bool IsValid();
}
public abstract class SampleObjectBase : ISampleObject
{
public virtual bool IsValid()
{
var returnValue = true; //VH: Changed value from false to true
// Self-validation sets the return value.
var childProperties = this.GetType().GetProperties().Where(pi => typeof(ISampleObject).IsAssignableFrom(pi.PropertyType));
foreach (var childProperty in childProperties)
{
//VH: Here is how you get the value of the property
var childInstance = (ISampleObject)childProperty.GetValue(this, null);
if (childInstance.IsValid() != true)
{
returnValue = false;
}
}
return returnValue;
}
}
public sealed class InnerSampleObject : SampleObjectBase
{
}
public sealed class OuterSampleObject : SampleObjectBase
{
//VH: Added this constructor
public OuterSampleObject()
{
DerivedSampleObject = new InnerSampleObject();
}
public InnerSampleObject DerivedSampleObject { get; set; }
}
class Program
{
static void Main(string[] args)
{
OuterSampleObject c = new OuterSampleObject();
c.IsValid();
}
}
Ответ №3:
Просто используйте
var childInstance = (ISampleObject)childProperty.GetValue(this, null);