0

This is a two-part question. First, which of these explicit property implementations gets bound to IAllTogether.SomeInt and why doesn't the compiler complain about ambiguity? It does when you comment-out the marked lines.

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;

Second question would be: how do I find the right PropertyInfo when given an interface Type and a name of the property? I can use GetInterfaces() and GetProperty() to list all the possible candidates, but how do I know which is the right one? I tried typeof(IAllTogether).GetProperty("SomeInt"), but it doesn't work.

Edit

Looks like the answer to the first part is that the hiding of inherited members resolves ambiguity. However, not even a single comment yet on the second part: how to reliably find the proper PropertyInfo for some property name and an interface type.

Edit 2

Clarification on the second part of the question. What I'm looking for is a way to get the right property for any unknown Type. Basically, a method like this:

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
}
klashar
  • 2,519
  • 2
  • 28
  • 38
relatively_random
  • 4,505
  • 1
  • 26
  • 48
  • 1
    If I run that code I can see that the one from `ICombined` is called, probably because of the `new` keyword that hides the other two. Btw: ReSharper tells me that explicitly stating `IFirst` and `ISecond` at the declaration of `IAllTogether` is redundant as they are inherited anyway through `ICombined`. – René Vogt Feb 07 '17 at 16:40
  • because `SomeInt` in either `IFirst` and `ISecond` is now hidden by `new SomeInt` in `ICombined`, therefore `ICombined.SomeInt` will be used. `ICombined.SomeInt` has higher priority than two other not because of `new` keyword. but because `ICombined` implements two other interfances. therefore it can hide their members. – M.kazem Akhgary Feb 07 '17 at 16:50
  • 1
    ill let you know if I found answer to second part. – M.kazem Akhgary Feb 07 '17 at 16:51
  • Could you specify or give an example to that second question? I added a line to my answer. _What_ value do you have that you want to get a property of? The correct property is `typeof(ICombined).GetProperty("SomeInt")`. If the commented lines are removed it depends on what you are actually calling. – René Vogt Feb 07 '17 at 16:54
  • @RenéVogt Imagine you're writing a method that takes a Type parameter and a string parameter: an interface type and the name of the parameter. The method needs to return the right PropertyInfo object. You don't know anything about IAllTogether or ICombined. I'll edit the answer to clarify. – relatively_random Feb 07 '17 at 16:56
  • @relatively_random I understood that, but see my edited answer: What is your criteria for the "correct" property? All three properties can be accessed. There is no "correct" one. – René Vogt Feb 07 '17 at 16:59
  • @RenéVogt All three of them can be accessed if you cast your object to different types. The problem is how to programatically get the property that will get called when using the *given* interface type. – relatively_random Feb 07 '17 at 17:01
  • Answer to your second part lies at: http://stackoverflow.com/questions/358835/getproperties-to-return-all-properties-for-an-interface-inheritance-hierarchy – Versatile Feb 07 '17 at 19:28
  • @Versatile I did read through that, thank you. It answers a similar question of finding all properties of an interface. This is about finding the specific property "overload". – relatively_random Feb 08 '17 at 09:05

2 Answers2

1

Lots of people answered the first part: if an interface hides members of the original interface, those are not considered.

Using that information, here's my attempt at the second part. Comments on issues or improvements are welcome.

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();
}
relatively_random
  • 4,505
  • 1
  • 26
  • 48
0

To answer your first question.

Compiler only need to know is that the interface members are implemented or not. It is the runtime who decides which version of the member to invoke.

In your example you are using explicit implementation.

In this case compile first checks if SomeInt property is implemented or not. If that is implicitly implemented it won't complain. If any one of the interface property is implemented explicitly compiler will check if rest o the interface properties are implemented either by implicit or explicit.

Chetan
  • 6,711
  • 3
  • 22
  • 32
  • Sorry, but I don't understand. How does the runtime decide which one of these explicit implementations to call for an object of type `Implementation` accessed through a reference of type `IAllTogether`? – relatively_random Feb 07 '17 at 16:42
  • It will use version of `ICombined` as it has the interface member hiding the member of it's parent interfaces and also Even if it is not hiding the parent member it is the unique immediate parent of IAllTogether. So it comes to the common Inheritance rule that look for the self member, if found invoke it else look upwards and try to find in the immediate parent, if found invoke it else loo upwards and so on. – Chetan Feb 07 '17 at 16:58