views:

135

answers:

4

Dear ladies and sirs.

I have a type and an interface and I need to verify that the type implements the interface abstractly.

I have set to write a brute force code using Reflection and it is pretty ugly.

I am wondering if there is a better way than the brute force implementation I am doing now.

Any ideas?

Thanks.

EDIT

Have not checked the implementation yet, but the brute force draft code looks like this:

  public static bool IsAbstractInterfaceImplementation(Type someType, Type someInterface)
  {
    if (!someInterface.IsAssignableFrom(someType))
    {
      return false;
    }

    if (!someType.IsAbstract)
    {
      return false;
    }

    var m_interfaceMemberNames = someInterface.GetMembers().Select(m => m.Name).ToList();
    // Make sure every interface member implementation is abstract.
    foreach (var typeMember in someType.FindMembers(MemberTypes.Event | MemberTypes.Property | MemberTypes.Method, BindingFlags.Public | BindingFlags.Instance, null, null))
    {
      if (m_interfaceMemberNames.Contains(typeMember.Name))
      {
        MethodInfo method;
        // Make sure the ancestor member is abstract.
        switch (typeMember.MemberType)
        {
        case MemberTypes.Event:
          if (!IsAbstractImplementation(((EventInfo)typeMember).GetAddMethod()))
          {
            return false;
          }
          method = ((EventInfo)typeMember).GetRemoveMethod();
          break;
        case MemberTypes.Property:
          method = ((PropertyInfo)typeMember).GetGetMethod();
        default:
          method = (MethodInfo)typeMember;
          break;
        }
        if (!IsAbstractImplementation(method))
        {
          return false;
        }
      }
    }
    return true;
  }

  public static bool IsAbstractImplementation(MethodInfo methodInfo)
  {
    const MethodAttributes expectedAttributes =
      MethodAttributes.Abstract |
      MethodAttributes.Public |
      MethodAttributes.NewSlot |
      MethodAttributes.Virtual;

    return (methodInfo.Attributes & expectedAttributes) == expectedAttributes;
  }

Without compiling it I already see a problem with properties, that the code has to check whether interface defines getter and/or setter and verify the right method(s), instead of blindly assuming the getter. Anyway, as one can see, the code is pretty dull. I am wondering if there is a better way...

EDIT 2

  • I wish to stress, that this is just a draft implementation, it works for simple cases and it is broken for more complex ones, like when there are method overloads or method renames (I do not know VB, so I did not even think it was possible). But it emphasizes my point that it demands much work to do it right.
  • Why would I want such a thing? We need to create types dynamically using Reflection.Emit based on certain dynamically acquired metadata. The generated dynamic type implements certain interface, say IDynamicObject, and may derive from some ancestor type. That ancestor type is statically compiled. Until recently, the ancestor type was not allowed to implement the IDynamicObject interface. Given an instance of the dynamic type, one had to explicitly cast it to IDynamicObject in order to gain access to its methods (remember, that the generated dynamic type does implement the interface). I would like to eliminate these explicit casts. The only way to do so is by letting the ancestor type implement the IDynamicObject interface. However, the implementation must be all abstract, which is verified by the dynamic type creation code. Voila.
+7  A: 

You can determine if a type implements a particular interface by using Type.IsAssignableFrom:

typeof(MyInterface).IsAssignableFrom(abstractType);

Edit: after clarification was added to the answer - to determine if all of an interface's implementations are abstract for a given class, you can do so much more easily by getting an InterfaceMap for the type in question:

bool IsAbstractOfInterface(Type classType, Type interfaceType)
{
    var map = classType.GetInterfaceMap(interfaceType);
    foreach (var info in map.TargetMethods)
    {
        if (!info.IsAbstract)
        {
            return false;
        }
    }
    return true;
}

Or maybe a generic extension method...

public static bool IsAbstractOf<TInterface>(this Type type)
{
    var map = type.GetInterfaceMap(typeof(TInterface));
    foreach (var info in map.TargetMethods)
    {
        if (!info.IsAbstract)
        {
            return false;
        }
    }
    return true;
}
Rex M
It is known that the type implements the interface. What I need is whether the implementation is all abstract.
mark
@Mark there is no way to know without reflecting each member to see if it is abstract.
Rex M
I suspect that. But may be there are reflection related tricks that I am not aware of.
mark
@Mark there are not.
Rex M
Thanks, using the IntefaceMap is the trick I was looking for.
mark
A: 

Rex M's answer is correct in general, but if your type is a type parameter, you can also do:

class Foo<T> where T : IWhatever {
    // Do your thing, secure in the knowledge that T implements IWhatever
}
David Seiler
It is known that the type implements the interface. What I need is whether the implementation is all abstract.
mark
A: 
public static bool IsAbstractInterfaceImplementation(Type someType, Type someInterface)
{
    return someType.IsAbstract && someInterface.IsAssignableFrom(someType);
}
Thomas Levesque
This only determines if the class is abstract, not whether certain methods are abstract.
Rex M
A: 

You cannot use the member names. BEcause there's no reason to assume, that the name of a member tells you anything about the interface member it implements. Reflection provides you with means to see which method implements which one from the interface, though.

Here's a snippet that would return all method on a given type that are implemented only abstractly.

static IEnumerable<MethodInfo> GetAbstractImplementations(this Type implementingType, Type interfaceType)
{
    if(!interfaceType.IsInterface)
     throw new ArgumentException(interfaceType.FullName + " is not an interface.");
    if(implementingType.IsInterface)
     throw new ArgumentException(interfaceType.FullName + " is an interface.");

    if(!interfaceType.IsAssignableFrom(implementingType))
     throw new ArgumentException(implementingType.FullName + " does not implement " + interfaceType.FullName + ".");

    var mapping = implementingType.GetInterfaceMap(interfaceType);
    return from m  in mapping.TargetMethods 
        where m.IsAbstract
        select m;
}

public static bool IsAbstractInterfaceImplementationOf(this Type implementingType, Type interfaceType)
{
    return implementingType.GetAbstractImplementations(interfaceType).Any();
}
Robert Giesecke