问题 如何使用反射来查找实现特定接口的属性?


考虑这个例子:

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语句,替换 某物 用正确的代码?

编辑:

我注意到我应该使用属性而不是字段来实现这一点,所以它应该是:

    public Object catList
    {
        get
        {
          return new List<Cat>();
        }
    }

10174
2018-06-20 17:07


起源

没有。这不是功课。 - Stephen Oberauer
@bzlm,谁会把这作为作业?锁定他的个人资料他是33 .. - Shuhel Ahmed
@shuhel我认为你需要了解一些关于互联网的事情...... - bzlm
我没有简单地将我的商业软件问题复制并粘贴到这个屏幕上,而是花了一些时间来简化它,以便其他人更容易帮助我解决这个问题。这可能就是为什么bzlm认为它看起来像家庭作业。我实际上是33岁......但我并不总是这样:) - Stephen Oberauer


答案:


你可以看一下这些房产 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>
    }                           
}

当然,如果你想让上面的代码工作,你需要为你的类添加一个属性;-)


14
2018-06-20 17:12



问题可能是您将值键入为对象 - 您可以将任何内容分配给对象。因此,如果您想保留它,您可能需要查看属性的运行时值,假设您有一个值。 - driis
我不认为这会起作用 - 不应该这样 if((typeof(IEnumerable<IAnimal>).IsAssignableFrom(property.PropertyType)) ?? - BrokenGlass
@BrokenGlass,当然,你是对的(修复了答案)。 - driis


请注意,在您的示例中,找不到catList GetType().GetProperties ()。你会用的 GetType().GetFields () 代替。

如果您要确定该属性是否定义为IEnumerable,则可以执行以下操作:

if (typeof(IEnumerable<IAnimal>) == property.PropertyType)
{
   MessageBox.Show("animal list found");
}

如果您想知道是否可以将属性的值分配给a 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");
}

1
2018-06-20 17:14



当我正在正确地阅读这个问题时,重点是在不知道价值的情况下进行,只有使用反射获得的类型。 - driis
我没有这样解释,但我会解决这个问题,以防万一。 - agent-j
agent-j:关于.GetFields()... oops的好点。 - Stephen Oberauer
对于我的目的,无论你是在检查实例还是类型......我都在使用反射,因为我不知道运行时包含类会有哪些属性...如果这是有道理的。无论如何,您的解决方案有效。谢谢! - Stephen Oberauer


另一种方法是打电话 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));

编辑:我刚刚注意到你的例子是一个集合,这对整个传递的集合无效。您必须单独传递每个项目。我很想删除,但这可能会帮助其他人在谷歌这个同样的问题寻找非收集解决方案。


1
2018-05-10 22:56