I have a property on a class which is implemented by an interface. Now I want to get all attributes from a specific type declared on that property and their interface Pendants.
In order to regard multi implementation wich implicit and explicit members I wrote an test-class (with xUnit).
[DebuggerDisplay("{Tooltip}")]
[AttributeUsage(AttributeTargets.Property)]
public class TooltipAttribute : Attribute
{
public TooltipAttribute(string tooltip)
{
Tooltip = tooltip;
}
public string Tooltip { get; set; }
}
public interface IAmGood
{
[Tooltip("GOOD: I am a very generic description.")]
int Length { get; }
}
public interface IAmBad
{
[Tooltip("BAD: This description is not wanted to be shown.")]
int Length { get; }
}
public class DemoClassImplicit : IAmGood, IAmBad
{
[Tooltip("GOOD: Implicit")]
public int Length => throw new NotImplementedException();
[Tooltip("BAD: Explicit")]
int IAmBad.Length => throw new NotImplementedException();
}
public class DemoClassExplicit : IAmGood, IAmBad
{
[Tooltip("GOOD: Explicit")]
int IAmGood.Length => throw new NotImplementedException();
[Tooltip("BAD: Implicit")]
public int Length => throw new NotImplementedException();
}
public class DemoClassImplicitForBoth : IAmGood, IAmBad
{
[Tooltip("I am GOOD and BAD")]
public int Length => throw new NotImplementedException();
}
public class TestClass
{
[Fact]
public void GetTooltipFromImplicit()
{
var demoClassImplicit = new DemoClassImplicit();
var propertyInfo = demoClassImplicit.GetType().GetRuntimeProperty("Length");
var tooltips = GetTooltipAttribute<TooltipAttribute>(propertyInfo);
Assert.Equal(2, tooltips.Count());
Assert.All(tooltips, o => Assert.Contains("GOOD", o.Tooltip));
}
[Fact]
public void GetTooltipFromExplicit()
{
var demoClassImplicit = new DemoClassExplicit();
var propertyInfo = demoClassImplicit.GetType().GetRuntimeProperties().First(o => o.Name.EndsWith(".Length"));
var tooltips = GetTooltipAttribute<TooltipAttribute>(propertyInfo);
Assert.Equal(2, tooltips.Count());
Assert.All(tooltips, o => Assert.Contains("GOOD", o.Tooltip));
}
[Fact]
public void GetTooltipFromImplicitForBoth()
{
var demoClassImplicit = new DemoClassImplicitForBoth();
var propertyInfo = demoClassImplicit.GetType().GetRuntimeProperty("Length");
var tooltips = GetTooltipAttribute<TooltipAttribute>(propertyInfo);
Assert.Equal(3, tooltips.Count());
}
/// <summary>
/// The core method.
/// </summary>
public IEnumerable<T_Attribute> GetTooltipAttribute<T_Attribute>(PropertyInfo propInfo)
where T_Attribute : Attribute
{
var result = new List<T_Attribute>(propInfo.GetCustomAttributes<T_Attribute>());
var declaringType = propInfo.DeclaringType;
// The get method is required for comparing without use the prop name.
var getMethodFromGivenProp = propInfo.GetGetMethod(true);
// Check for each interface if the given property is declared there
// (it is not a naming check!).
foreach (var interfaceType in declaringType.GetInterfaces())
{
var map = declaringType.GetInterfaceMap(interfaceType);
// Check if the current interface has an member for given props get method.
// Attend that compare by naming would be cause an invalid result here!
var targetMethod = map.TargetMethods.FirstOrDefault(o => o.Equals(getMethodFromGivenProp));
if (targetMethod != null)
{
// Get the equivalent get method on interface side.
// ERROR: The error line!
var interfaceMethod = map.InterfaceMethods.FirstOrDefault(o => o.Name == targetMethod.Name);
if (interfaceMethod != null)
{
// The get method does not help to get the attribute so the property is required.
// In order to get the property we must look which one has the found get method.
var property = interfaceType.GetProperties().FirstOrDefault(o => o.GetGetMethod() == interfaceMethod);
if (property != null)
{
var attributes = property.GetCustomAttributes<T_Attribute>();
if (attributes != null)
{
result.AddRange(attributes);
}
}
}
}
}
return result;
}
}
The test method 'GetTooltipFromExplicit' failes because in the core method is a comparison by name. I marked the line above with // ERROR: The error line!
.
I have no idea how to find the method-pendant inside of 'InterfaceMapping'-class.
Aucun commentaire:
Enregistrer un commentaire