想象一下你有这个界面:
interface ITest
{
bool MyProperty { get; set; }
}
在这个类中实现:
class Test : ITest
{
bool ITest.MyProperty { get; set; }
}
现在让我们将此属性添加到Test
(注意它们具有相同的名称):
public bool MyProperty { get; set; }
使用plain GetProperties()
,您将无法获得显式接口实现(因为它始终是私有成员):
int count = new Test().GetType().GetProperties().Length; // It's 1!
如果您同时包含Public
和NonPublic
成员,您将同时获得两者。为了区分它们,您可以首先依赖名称:显式实现将包含完整的接口名称(因此您可以查找 a .
,它不会出现在普通属性中,因为它不是允许的字符):
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;
}
当然不是所有这些检查都需要,我认为前两个足以排除大部分编译器生成的代码。
如果您知道可以显式实现哪个接口,您会发现这个问题非常有用:如何查找方法是否正在实现特定接口
编辑
从评论中我想到了这一点,我发现没有合适的方法来做到这一点,CLR 不应用任何规则(AFAIK),因为所需要的只是接口方法和类方法之间的链接(不管它是如何调用的)。我想(但对于其他语言可能会放宽或扩展,如果有人愿意提供更多测试,我会将这个答案作为 wiki)此代码在大多数情况下可能有效(感谢 Alxandr 的提示):
第一个检查方法(给定 a MethodInfo
)是否是显式接口实现的通用函数。
我们不能断言:
我们可以断言:
这是代码:
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's 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's 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's 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's a pretty corner case
// so we may just ignore it.
if (property.GetMethod != null)
return IsExplicitInterfaceImplementation(property.GetMethod);
return IsExplicitInterfaceImplementation(property.SetMethod);
}