Tyson Williams
Tyson Williams

Reputation: 1725

Missing Custom Attriubutes

In C#, one can use reflection to obtain the attributes on a member m via m.CustomAttributes (see the documentation for this property). However, this approach seems to miss three custom attributes on the GetType method of Object (see the Object in the Reference Source for .NET Framework 4.6.1):

using System;
using System.Linq;
namespace ConsoleApplication1 {
  public class Program {
    public static void Main(string[] args) {
      var desiredCustomAttributes = typeof(object)
        .GetMethods()
        .First(m => m.Name == "GetType")
        .CustomAttributes
        .Select(ca => ca.ToString())
        .Where(s =>
          s.Contains("Pure") ||
          s.Contains("ResourceExposure") ||
          s.Contains("MethodImplAttribute"));
      var n = desiredCustomAttributes.Count();
      Console.WriteLine("Expected: 3");
      Console.WriteLine("  Actual: " + n); // prints "  Actual: 0"
      Console.ReadKey();
    }
  }
}

Why do these three custom attributes not show up?

Maybe it has something to do with the fact that it is an external method?

Actually, being external has nothing to do with it.

using System;
using System.Linq;
using System.Runtime.Versioning;
namespace ConsoleApplication1 {
  public class ResourceExposureAttributeOnConstructor {
    [ResourceExposure(ResourceScope.None)]
    public ResourceExposureAttributeOnConstructor() { }
  }
  public class Program {
    public static void Main(string[] args) {
      var n = typeof(object)
        .GetConstructors()
        .First()
        .CustomAttributes
        .Select(ca => ca.ToString())
        .Where(s => s.Contains("ResourceExposure"))
        .Count();
      Console.WriteLine("Expected: 1");
      Console.WriteLine("  Actual: " + n); // prints "  Actual: 0"
      Console.ReadKey();
    }
  }
}

Upvotes: 1

Views: 720

Answers (1)

Cheng Chen
Cheng Chen

Reputation: 43523

It's not because the method is external. Tried with a user defined class:

class MyAttr : Attribute { }
class Program
{
    [Pure]
    [ResourceExposure(ResourceScope.AppDomain)]
    [MethodImpl]
    [MyAttr]
    public void Foo() { }
}

.CustomAttributes returns MyAttr only. I think it's simply because FCL don't threat the three attributes as custom attributes. Looking into the source code, MethodInfo.CustomAttributes finally invokes MetadataImport.EnumCustomAttributes, where an external method is called.

[SecurityCritical]
[MethodImpl(MethodImplOptions.InternalCall)]
private static extern void _Enum(IntPtr scope, int type, int parent, out MetadataEnumResult result);

I didn't debug into it, but I think it makes sense that this method knows some built-in attributes and excludes them from custom attributes.

EDIT PureAttribute and ResourceExposureAttribute are conditionally built, that's why you can't get them.

[Conditional("RESOURCE_ANNOTATION_WORK")]
public sealed class ResourceExposureAttribute : Attribute

[Conditional("CONTRACTS_FULL")]
public sealed class PureAttribute : Attribute

It seems that MethodImplAttribute is special.

Upvotes: 1

Related Questions