How to check whether one .NET type implements certain .NET interface abstractly?
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 der开发者_如何学编程ive 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.
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'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
}
public static bool IsAbstractInterfaceImplementation(Type someType, Type someInterface)
{
return someType.IsAbstract && someInterface.IsAssignableFrom(someType);
}
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();
}
精彩评论