通过反射正确地找到继承的接口属性

时间:2017-02-07 16:26:39

标签: c# reflection properties interface language-lawyer

这是一个由两部分组成的问题。首先,这些显式属性实现中的哪一个绑定到IAllTogether.SomeInt,为什么编译器不抱怨模糊性?当您注释掉标记的行时,它会这样做。

public interface IFirst
{
    int SomeInt { get; }
}

public interface ISecond
{
    int SomeInt { get; }
}

public interface ICombined : IFirst, ISecond
{
    new int SomeInt { get; } // Comment this line.
}

public interface IAllTogether : IFirst, ISecond, ICombined
{ }

public sealed class Implementation : IAllTogether
{
    int ICombined.SomeInt { get { return 0; } } // Comment this line.

    int IFirst.SomeInt { get { return 0; } }

    int ISecond.SomeInt { get { return 0; } }
}


IAllTogether t = new Implementation();
var unimportant = t.SomeInt;

第二个问题是:在给定接口PropertyInfo和属性名称时,如何找到正确的Type?我可以使用GetInterfaces()GetProperty()列出所有可能的候选人,但我怎么知道哪个是正确的?我试过了typeof(IAllTogether).GetProperty("SomeInt"),但它不起作用。

修改

看起来第一部分的答案是隐藏继承成员可以解决歧义问题。但是,第二部分甚至还没有一条评论:如何为某些属性名称和接口类型可靠地找到正确的PropertyInfo

编辑2

澄清问题的第二部分。我正在寻找的是为任何未知Type获取正确属性的方法。基本上,这样的方法:

public static PropertyInfo GetPropertyOfInterface(Type interfaceType, string propertyName)
{
    if (!interfaceType.IsInterface)
        throw new ArgumentException();

    // for interfaceType == typeof(IAllTogether), return ICombined.SomeInt
    // for interfaceType == typeof(IFirst), return IFirst.SomeInt
}

2 个答案:

答案 0 :(得分:1)

很多人回答了第一部分:如果某个界面隐藏了原始界面的成员,则不会考虑这些界面。

使用这些信息,这是我在第二部分的尝试。欢迎提出有关问题或改进的评论。

public static PropertyInfo GetPropertyOfInterface(Type interfaceType, string propertyName)
{
    if (interfaceType == null)
        throw new ArgumentNullException("interfaceType");

    if (!interfaceType.IsInterface)
        throw new ArgumentException(
            string.Format("Type {0} doesn't represent an interface.",
                interfaceType.FullName),
            "interfaceType");

    // If declared in given interface, just return that.
    var declaredProperty = interfaceType.GetProperty(propertyName);
    if (declaredProperty != null)
        return declaredProperty;

    // Otherwise, first finding all the candidates.
    var candidates = new HashSet<PropertyInfo>(
        interfaceType.GetInterfaces().Select(t => t.GetProperty(propertyName)));
    candidates.Remove(null);

    if (candidates.Count == 0)
        throw new ArgumentException(
            string.Format("Property {0} not found in interface {1}.",
                propertyName, interfaceType.FullName),
            "propertyName");

    // Finally, removing all candidates the first candidates hide.
    var originalCandidates = candidates.ToList();
    candidates.ExceptWith(
        originalCandidates.SelectMany(prop => prop.DeclaringType.GetInterfaces())
                          .Select(t => t.GetProperty(propertyName)));

    if (candidates.Count != 1)
        throw new AmbiguousMatchException(
            string.Format("Property {0} is ambiguous in interface {1}.",
                propertyName, interfaceType.FullName));

    return candidates.First();
}

答案 1 :(得分:0)

回答你的第一个问题。

编译器只需知道接口成员是否已实现。运行时决定要调用的成员版本。

在您的示例中,您使用的是显式实现。

在这种情况下,编译首先检查是否实现了SomeInt属性。如果这是隐含的实施,它就不会抱怨。如果显式实现了任何一个接口属性,编译器将检查接口属性是否通过隐式或显式实现。