У меня есть тип и интерфейс, и мне нужно убедиться, что тип реализует интерфейс абстрактно.
Я решил написать код грубой силы, используя Reflection, и это довольно уродливо.
Мне интересно, есть ли лучший способ, чем реализация грубой силы, которую я делаю сейчас.
Есть идеи?
Спасибо.
EDIT
Еще не проверили реализацию, но черновой код грубой силы выглядит так:
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;
}
Не компилируя его, я уже вижу проблему со свойствами, заключающуюся в том, что код должен проверять, определяет ли интерфейс геттер и / или сеттер, и проверять правильные методы, вместо того, чтобы слепо предполагать геттер. В любом случае, как видите, код довольно скучный. Мне интересно, есть ли лучший способ ...
РЕДАКТИРОВАТЬ 2
- Хочу подчеркнуть, что это всего лишь черновая реализация, она работает для простых случаев и не работает для более сложных, например, когда есть перегрузки методов или переименования методов (я не знаю VB, поэтому я не сделал даже думаю, что это возможно). Но это подчеркивает мою точку зрения, что для того, чтобы сделать это правильно, требуется много работы.
- Зачем мне такая вещь? Нам нужно создавать типы динамически, используя Reflection.Emit на основе определенных динамически полученных метаданных. Сгенерированный динамический тип реализует определенный интерфейс, скажем, IDynamicObject, и может происходить от некоторого предкового типа. Этот тип предка статически компилируется. До недавнего времени типу предка не разрешалось реализовывать интерфейс IDynamicObject. Учитывая экземпляр динамического типа, нужно было явно привести его к IDynamicObject, чтобы получить доступ к его методам (помните, что сгенерированный динамический тип действительно реализует интерфейс). Я хотел бы устранить эти явные приведения. Единственный способ сделать это - позволить типу предка реализовать интерфейс IDynamicObject. Однако реализация должна быть полностью абстрактной, что подтверждается кодом создания динамического типа. Вуаля.