Отражение над вложенными экземплярами без создания нового экземпляра - PullRequest
1 голос
/ 07 мая 2011

Я немного боролся с каким-то кодом отражения, который я хотя бы был простым. По сути, у меня есть интерфейс, который определяет метод. Затем у меня есть абстрактный класс, который обеспечивает базовую реализацию этого метода.

Конкретные классы могут содержать вложенные экземпляры других классов, которые также могут быть производными от того же базового класса. Это можно проиллюстрировать на следующем примере:

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.IsValid (), код находит PropertyInfo для InnerSampleObject, как и ожидалось. Я хочу выполнить InnerSampleObject.IsValid ().

Я пробовал (несколько вариантов):

var childIsValid = (bool)contractProperty.PropertyType.InvokeMember("IsValid", BindingFlags.InvokeMethod, null, null, null);

И

var childInstance = (ISampleContract)contractProperty;

Проблема с первым заключается в том, что я не могу передать значение null в качестве цели для InvokeMember, поскольку IsValid () не является статическим (и не может быть, поскольку я сосредоточен на фактическом экземпляре). Второй - просто неудачный актерский состав, но это суть того, чего я хочу достичь.

Пример кода выше - просто минималистский пример того, чего я хочу достичь. Полный код является частью самопроверяющегося DTO, который рекурсивно проверяет всю иерархию и возвращает то, что у детей есть проблемы с проверкой и чем они являются.

Любая помощь будет принята с благодарностью.

Ответы [ 3 ]

2 голосов
/ 07 мая 2011

Как насчет:

var instance = childProperty.GetValue(this, null) as ISampleObject;
if (instance != null)
{
  if (!instance.IsValid())
    return false;
}
1 голос
/ 07 мая 2011

Просто используйте

var childInstance = (ISampleObject)childProperty.GetValue(this, null);
1 голос
/ 07 мая 2011

Пожалуйста, посмотрите, является ли код ниже тем, что вы ищете. Мои изменения помечены комментарием, начинающимся с //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();

    }
}
...