反射嵌套实例而不创建新实例

发布于 2024-11-05 19:21:27 字数 1801 浏览 1 评论 0原文

我一直在努力处理一些我认为很简单的反射代码。本质上,我有一个定义方法的接口。然后,我有一个抽象类,它提供该方法的基本实现。

具体类可以包含其他类的嵌套实例,这些类也可以从同一基类派生。可以通过以下示例来说明:

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() 时,代码会按预期找到 InnerSampleObject 的 PropertyInfo。我想执行 InnerSampleObject.IsValid()。

我已经尝试过(多种变体):

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

并且:

var childInstance = (ISampleContract)contractProperty;

第一个的问题是我无法将 null 作为 InvokeMember 的目标传递,因为 IsValid() 不是静态的(也不能是静态的,因为我专注于实际情况)。第二个只是一个蹩脚的演员阵容,但却是我想要完成的要点。

上面的示例代码只是我想要实现的目标的一个极简示例。完整的代码是自验证 DTO 的一部分,它递归地检查整个层次结构并返回哪些子项存在验证问题以及它们是什么。

任何帮助将不胜感激。

I have been struggling a bit with some reflection code that I though would be simple. Essentially, I have an interface that defines a method. Then, I have an abstract class that provides a base implementation of that method.

The concrete classes can contain nested instances of other classes that can also derive from the same base class. It can be illustrated by the following sample:

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; }    
}

My problem is that in the commented code for SampleObjectBase, I cannot get the concrete instance of the matching PropertyInfo value. If I look at the PropertyInfo object in the loop, I see that the type is correct, but I cannot find a way to directly access the instance that already exists in the implementation. So, when executing, for example, OuterSampleObject.IsValid(), the code finds the PropertyInfo for InnerSampleObject, as expected. I want to execute InnerSampleObject.IsValid().

I have tried (multiple variations of):

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

And:

var childInstance = (ISampleContract)contractProperty;

The problem with the first one is that I can't pass null in as the target for InvokeMember, as IsValid() is not static (nor can it be, since I am focused on the actual instance). The second on is just a lame cast, but is the gist of what I want to accomplish.

The sample code above is just a minimalist example of what I want to achieve. The full code is part of a self-validating DTO that recursively checks the entire hierarchy and returns what children have validation issues and what they are.

Any help would be greatly appreciated.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

傲鸠 2024-11-12 19:21:27

怎么样:

var instance = childProperty.GetValue(this, null) as ISampleObject;
if (instance != null)
{
  if (!instance.IsValid())
    return false;
}

How about:

var instance = childProperty.GetValue(this, null) as ISampleObject;
if (instance != null)
{
  if (!instance.IsValid())
    return false;
}
海的爱人是光 2024-11-12 19:21:27

请查看下面的代码是否是您要查找的内容。我的更改标有以 //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();

    }
}

Please see if the code below is what you are looking for. My changes are marked with a comment starting with //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();

    }
}
记忆之渊 2024-11-12 19:21:27

只需使用

var childInstance = (ISampleObject)childProperty.GetValue(this, null);

Just use

var childInstance = (ISampleObject)childProperty.GetValue(this, null);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文