Ответ 1
Представьте, что у вас есть этот интерфейс:
interface ITest
{
bool MyProperty { get; set; }
}
Реализовано в этом классе:
class Test : ITest
{
bool ITest.MyProperty { get; set; }
}
Теперь добавьте это свойство в Test
(обратите внимание, что они имеют одинаковое имя):
public bool MyProperty { get; set; }
С простым GetProperties()
вы не получите явную реализацию интерфейса (потому что это всегда частный член):
int count = new Test().GetType().GetProperties().Length; // It 1!
Если вы включаете в себя как членов Public
, так и NonPublic
, вы получите оба. Чтобы отличить их, вы можете положиться сначала на имя: явная реализация будет содержать полное имя интерфейса (так что вы можете искать .
, он не будет там для нормального свойства, потому что это не разрешенный char):
public static bool IsExplicitInterfaceImplementation(PropertyInfo property)
{
return property.Name.Contains(".");
}
Это немного наивно, поэтому вам может понадобиться дополнительная проверка, вы можете утверждать, что метод get этого свойства будет:
- Есть
virtual
иsealed
. - Есть
private
. - Содержит хотя бы одну точку.
- Не запускается с
get_
или_set
Изменить код:
public static bool IsExplicitInterfaceImplementation(PropertyInfo property)
{
// This check is not mandatory and not cross-languages.
// How this method is named may vary
if (!property.Name.Contains("."))
return false;
if (property.Name.StartsWith("get_"))
return false;
if (!property.GetMethod.IsFinal)
return false;
if (!property.GetMethod.IsVirtual)
return false;
if (!property.GetMethod.IsPrivate)
return false;
return true;
}
Конечно, не все эти проверки необходимы, я думаю, что первых двух достаточно, чтобы исключить большую часть кода, сгенерированного компилятором.
Если вы знаете, какой интерфейс может быть явно реализован, вы найдете здесь этот вопрос на SO довольно полезным: Как найти, реализует ли метод определенный интерфейс
ИЗМЕНИТЬ
Из комментариев, которые я подумал об этом, и я обнаружил, что нет правильного способа сделать это, CLR не применяет какое-либо правило (AFAIK), потому что необходимо только соединение между методом интерфейса и методом класса (как бы оно ни называлось). Я полагаю (но он может быть расслабленным или расширенным для других языков, если кто-то внесет вклад с большим количеством тестов, я сделаю этот ответ вики), этот код может работать в большинстве случаев (спасибо Alxandr за подсказку):
Первая общая функция для проверки того, является ли метод (с учетом MethodInfo
) явной реализацией интерфейса или нет.
То, что мы не можем утверждать:
-
Мы не можем использовать имя (для проверки, например, "." ), потому что он зависит от реализации (С# использует имя интерфейсаName.methodName, а на других языках нет).
-
Мы не можем полагаться на проверку для private, потому что (например) в С++/CLI это может быть общедоступный метод (с другим именем), кроме того, интерфейс может быть "взломан", чтобы быть внутренним, но разработчик быть общедоступным (поэтому метод также не будет публичным).
Что мы можем утверждать:
-
Явная реализация интерфейса всегда запечатана и виртуальна. Возможно, это "неверно" для всех языков, поэтому мы можем ослабить это правило.
-
Если метод не имеет то же имя метода, объявленного в интерфейсе, он реализует тогда явную реализацию.
Это код:
public static bool IsExplicitInterfaceImplementation(MethodInfo method)
{
// Check all interfaces implemented in the type that declares
// the method we want to check, with this we'll exclude all methods
// that don't implement an interface method
var declaringType = method.DeclaringType;
foreach (var implementedInterface in declaringType.GetInterfaces())
{
var mapping = declaringType.GetInterfaceMap(implementedInterface);
// If interface isn't implemented in the type that owns
// this method then we can ignore it (for sure it not
// an explicit implementation)
if (mapping.TargetType != declaringType)
continue;
// Is this method the implementation of this interface?
int methodIndex = Array.IndexOf(mapping.TargetMethods, method);
if (methodIndex == -1)
continue;
// Is it true for any language? Can we just skip this check?
if (!method.IsFinal || !method.IsVirtual)
return false;
// It not required in all languages to implement every method
// in the interface (if the type is abstract)
string methodName = "";
if (mapping.InterfaceMethods[methodIndex] != null)
methodName = mapping.InterfaceMethods[methodIndex].Name;
// If names don't match then it explicit
if (!method.Name.Equals(methodName, StringComparison.Ordinal))
return true;
}
return false;
}
С помощью этой вспомогательной функции для проверки свойств:
public static bool IsExplicitInterfaceImplementation(PropertyInfo property)
{
// At least one accessor must exists, I arbitrary check first for
// "get" one. Note that in Managed C++ (not C++ CLI) these methods
// are logically separated so they may follow different rules (one of them
// is explicit and the other one is not). It a pretty corner case
// so we may just ignore it.
if (property.GetMethod != null)
return IsExplicitInterfaceImplementation(property.GetMethod);
return IsExplicitInterfaceImplementation(property.SetMethod);
}