인터페이스를 명시 적으로 구현하기 위해 반사를 사용하려면 어떻게합니까?
-
07-07-2019 - |
문제
보다 구체적으로, 내가 가진 경우 :
public class TempClass : TempInterface
{
int TempInterface.TempProperty
{
get;
set;
}
int TempInterface.TempProperty2
{
get;
set;
}
public int TempProperty
{
get;
set;
}
}
public interface TempInterface
{
int TempProperty
{
get;
set;
}
int TempProperty2
{
get;
set;
}
}
반사를 사용하여 Tempinterface를 명시 적으로 구현하는 속성에 대한 모든 PropertyInfos를 얻으려면 어떻게해야합니까?
감사.
해결책 5
Jacob Carpenter의 답변을 수정해야했지만 잘 작동합니다. Nobugz는 또한 작동하지만 Jacobs는 더 작습니다.
var explicitProperties =
from method in typeof(TempClass).GetMethods(BindingFlags.NonPublic | BindingFlags.Instance)
where method.IsFinal && method.IsPrivate
select method;
다른 팁
당신이 찾고있는 클래스는 System.reflection.interfacempaping이라고 생각합니다.
Type ifaceType = typeof(TempInterface);
Type tempType = typeof(TempClass);
InterfaceMapping map = tempType.GetInterfaceMap(ifaceType);
for (int i = 0; i < map.InterfaceMethods.Length; i++)
{
MethodInfo ifaceMethod = map.InterfaceMethods[i];
MethodInfo targetMethod = map.TargetMethods[i];
Debug.WriteLine(String.Format("{0} maps to {1}", ifaceMethod, targetMethod));
}
명시 적으로 구현 된 인터페이스 속성의 속성 getter 및 setter는 특이한 속성을 가지고 있습니다. 봉인 된 클래스의 구성원이 아닌 경우에도 ISFinal 속성이 사실입니다. 내 주장을 확인하려면이 코드를 시도하십시오.
foreach (AssemblyName name in Assembly.GetEntryAssembly().GetReferencedAssemblies()) {
Assembly asm = Assembly.Load(name);
foreach (Type t in asm.GetTypes()) {
if (t.IsAbstract) continue;
foreach (MethodInfo mi in t.GetMethods(BindingFlags.NonPublic | BindingFlags.Instance)) {
int dot = mi.Name.LastIndexOf('.');
string s = mi.Name.Substring(dot + 1);
if (!s.StartsWith("get_") && !s.StartsWith("set_")) continue;
if (mi.IsFinal)
Console.WriteLine(mi.Name);
}
}
}
다음은 주어진 구현을 기반으로 수정 된 솔루션입니다. 이 블로그 게시물:
var explicitProperties =
from prop in typeof(TempClass).GetProperties(
BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly)
let getAccessor = prop.GetGetMethod(true)
where getAccessor.IsFinal && getAccessor.IsPrivate
select prop;
foreach (var p in explicitProperties)
Console.WriteLine(p.Name);
위에 Mrkurt의 답변:
var targetMethods =
from iface in typeof(TempClass).GetInterfaces()
from method in typeof(TempClass).GetInterfaceMap(iface).TargetMethods
select method;
var explicitProps =
from prop in typeof(TempClass).GetProperties(BindingFlags.Instance |
BindingFlags.NonPublic)
where targetMethods.Contains(prop.GetGetMethod(true)) ||
targetMethods.Contains(prop.GetSetMethod(true))
select prop;
지나치게 복잡합니다. 인터페이스 유형의 메소드/속성을 반영하고 클래스 유형에 존재하는지 확인하고 비교하여 존재할 때 "동일"인지 확인해야합니다.
인터페이스에 무언가가 있지만 테스트중인 유형이 아닌 경우 명시 적 구현입니다. 둘 다 있지만 둘 사이에 다른 경우, 그것은 명백한 인터페이스입니다.
Jacob의 코드는 필터가 없습니다.
var props = typeof(TempClass).GetInterfaces().Where(i => i.Name=="TempInterface").SelectMany(i => i.GetProperties());
foreach (var prop in props)
Console.WriteLine(prop);
이것은 명백한 이유없이 약간 고통스러워 보입니다!
내 해결책은 당신이 찾고있는 속성의 이름을 알고있는 경우이며 매우 간단합니다.
반사를 좀 더 쉽게 만들기위한 수업이 있습니다.
public class PropertyInfoWrapper
{
private readonly object _parent;
private readonly PropertyInfo _property;
public PropertyInfoWrapper(object parent, string propertyToChange)
{
var type = parent.GetType();
var privateProperties= type.GetProperties(BindingFlags.NonPublic | BindingFlags.Instance);
var property = type.GetProperty(propertyToChange) ??
privateProperties.FirstOrDefault(p => UnQualifiedNameFor(p) == propertyName);
if (property == null)
throw new Exception(string.Format("cant find property |{0}|", propertyToChange));
_parent = parent;
_property = property;
}
private static string UnQualifiedNameFor(PropertyInfo p)
{
return p.Name.Split('.').Last();
}
public object Value
{
get { return _property.GetValue(_parent, null); }
set { _property.SetValue(_parent, value, null); }
}
}
명시 적으로 구현 된 속성에는 자격을 갖춘 이름이 있기 때문에 이름으로 == 할 수 없습니다.
getProperties는 개인 속성으로 얻을 수있는 검색 플래그가 모두 필요합니다.
도움이 될 수있는 간단한 도우미 수업 :
public class InterfacesPropertiesMap
{
private readonly Dictionary<Type, PropertyInfo[]> map;
public InterfacesPropertiesMap(Type type)
{
this.Interfaces = type.GetInterfaces();
var properties = type.GetProperties(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public);
this.map = new Dictionary<Type, PropertyInfo[]>(this.Interfaces.Length);
foreach (var intr in this.Interfaces)
{
var interfaceMap = type.GetInterfaceMap(intr);
this.map.Add(intr, properties.Where(p => interfaceMap.TargetMethods
.Any(t => t == p.GetGetMethod(true) ||
t == p.GetSetMethod(true)))
.Distinct().ToArray());
}
}
public Type[] Interfaces { get; private set; }
public PropertyInfo[] this[Type interfaceType]
{
get { return this.map[interfaceType]; }
}
}
각 인터페이스에 대한 속성을 얻을 수 있으며 명시 적으로 구현됩니다.