lundi 1 août 2016

Reflection with generic syntax fails on a return parameter of an overridden method

To avoid old-fashioned non-generic syntax when searching for attributes of a known type, one usually uses the extension methods in System.Reflection.CustomAttributeExtensions class (since .NET 4.5).

However this appears to fail if you search for an attribute on the return parameter of an overridden method (or an accessor of an overridden property/indexer).

I am experiencing this with .NET 4.6.1.

Simple reproduction (complete):

using System;
using System.Reflection;

namespace ReflectionTrouble
{
  class B
  {
    //[return: MyMark("In base class")] // uncommenting does not help
    public virtual int M() => 0;
  }

  class C : B
  {
    [return: MyMark("In inheriting class")] // commenting away attribute does not help
    public override int M() => -1;
  }

  [AttributeUsage(AttributeTargets.ReturnValue, AllowMultiple = false, Inherited = false)] // commenting away AttributeUsage does not help
  sealed class MyMarkAttribute : Attribute
  {
    public string Descr { get; }

    public MyMarkAttribute(string descr)
    {
      Descr = descr;
    }

    public override string ToString() => $"MyMark({Descr})";
  }

  static class Program
  {
    static void Main()
    {
      var derivedReturnVal = typeof(C).GetMethod("M").ReturnParameter;

      // usual new generic syntax (extension method in System.Refelction namespace):
      var attr = derivedReturnVal.GetCustomAttribute<MyMarkAttribute>(); // BLOWS UP HERE, System.IndexOutOfRangeException: Index was outside the bounds of the array.
      Console.WriteLine(attr);

      // old non-generic syntax without extension method works:
      var attr2 = ((MyMarkAttribute[])(derivedReturnVal.GetCustomAttributes(typeof(MyMarkAttribute), false)))[0]; // OK
      Console.WriteLine(attr2);
    }
  }
}

The code may look "too long to read", but it is really just an overridden method with an attribute on its return parameter and the obvious attempt to retrieve that attribute instance.

Stack trace:

Unhandled Exception: System.IndexOutOfRangeException: Index was outside the bounds of the array.
   at System.Attribute.GetParentDefinition(ParameterInfo param)
   at System.Attribute.InternalParamGetCustomAttributes(ParameterInfo param, Type type, Boolean inherit)
   at System.Attribute.GetCustomAttributes(ParameterInfo element, Type attributeType, Boolean inherit)
   at System.Attribute.GetCustomAttribute(ParameterInfo element, Type attributeType, Boolean inherit)
   at System.Reflection.CustomAttributeExtensions.GetCustomAttribute[T](ParameterInfo element)
   at ReflectionTrouble.Program.Main() in c:\MyPath\Program.cs:line 38

Am I doing anything obviously wrong?

Is this a bug, and if yes, is it well-known, and is it an old bug?





Aucun commentaire:

Enregistrer un commentaire