想象一下,我有下面的代码。如何通过反映MemberInfo/PropertyInfo
Test.Name
的“显式”实现?
另外,有没有办法以编程方式知道MemberInfo
是接口属性的显式实现?
public interface ITest
{
string Title { get; set; }
}
public interface IExplicit
{
string Name { get; set; }
}
public class Test : ITest,IExplicit
{
public string Title { get; set; }
string IExplict.Name
{
get
{
return this.Title;
}
set
{
}
}
}
答案 0 :(得分:12)
想象一下,你有这个界面:
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
成员,则可以同时获得这两个成员。为了区分它们,您可以首先依赖名称:显式实现将包含完整的接口名称(因此您可以查找.
,它不会出现普通属性,因为它不是一个允许的字符):
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;
}
当然不是所有这些检查都是必需的,我认为前两个足以排除大多数编译器生成的代码。
如果您知道可以明确实施哪个界面,那么您可以在此处找到此问题非常有用:How to find if a method is implementing specific interface
修改强>
从评论我想到这一点,我发现没有一个正确的方法来做到这一点,CLR不应用任何规则(AFAIK),因为所需要的只是接口方法和类方法之间的链接(无论如何调用)。我想(但是对于其他语言可能会放宽或扩展,如果有人会通过更多测试做出贡献,我会将此答案作为维基)这段代码可能适用于大多数情况下(感谢Alxandr的提示):
检查方法(给定MethodInfo
)是否是显式接口实现的第一个通用函数。
我们无法断言:
我们不能使用name(检查,例如“。”)因为它依赖于实现(C#使用interfaceName.methodName,但其他语言没有)。
我们不能依赖于私有检查,因为(例如)在C ++ / 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'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);
}
答案 1 :(得分:2)
使用BindingFlags.Instance | BindingFlags.NonPublic
绑定标志来获取显式声明的成员。如果您想通过名称获取它们,还需要为显式成员指定全名:
Type type = typeof(Test);
var flags = BindingFlags.Instance | BindingFlags.NonPublic;
var property = type.GetProperty("Namespace.IExplicit.Name", flags);
您可以使用此事实仅过滤明确实施的成员:
var explicitMembers = type.GetMembers(flags).Where(m => m.Name.Contains("."));
答案 2 :(得分:1)
如果您的接口和类都位于同一名称空间中,您可以试试这个:
var interfaces = (typeof(Test)).GetInterfaces();
var p = typeof(Test).GetProperties(
BindingFlags.Instance |
BindingFlags.NonPublic);
var result = interfaces.SelectMany(i => i.GetMembers())
.Select(m =>
{
var name = m.DeclaringType.FullName +"."+ m.Name;
Console.WriteLine(name);
return name;
})
.Intersect(p.Select(m =>
{
Console.WriteLine(m.Name);
return m.Name;
}))
.ToList();
答案 3 :(得分:-1)
要获取特定接口属性的任何现有实现(impicit或explicit)的PropertyInfo,请使用以下代码:
var pInfoName = typeof(IExplicit).GetProperty("Name");
//...
Test tObj = new Test() { Title = "Test" };
string explicitName = (string)pInfoName.GetValue(tObj, new object[] { });
分类现有PropertyInfo使用@Adriano答案中显示的方法。