Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GetCustomAttributes behavior is different when used as extension method #30219

Closed
Evangelink opened this issue Jul 11, 2019 · 4 comments
Closed
Labels
area-System.Reflection question Answer questions and provide assistance, not an issue with source code or documentation.
Milestone

Comments

@Evangelink
Copy link
Member

Hi folks,

When doing a PR for fluentassertions/fluentassertions#1095 I have noticed a really strange behavior with GetCustomAttributes when using the inherits option.

Indeed this call CustomAttributeExtensions.GetCustomAttributes(property, true).OfType<TAttribute>().Any() returns true whereas property.GetCustomAttributes(true).OfType<TAttribute>().Any() returns false.

I have made a couple of tests and it seems that the bug happens only for PropertyInfo passed to the MemberInfo overload.

Given the following classes:

[AttributeUsage(AttributeTargets.Property, AllowMultiple = true, Inherited = true)]
internal class DummyPropertyAttribute : Attribute
{
}

internal class TestClassForPropertySelectorWithInheritableAttribute
{
    [DummyProperty]
    public virtual string PublicVirtualStringPropertyWithAttribute { get; set; }
}

internal class TestClassForPropertySelectorWithInheritableAttributeDerived : TestClassForPropertySelectorWithInheritableAttribute
{
}

This code doesn't work properly:

Type type = typeof(TestClassForPropertySelectorWithInheritableAttributeDerived);

// Returns 1
var classicMethodCallCount = type.GetProperties()
    .Count(property =>
        CustomAttributeExtensions.GetCustomAttributes(property, true).OfType<DummyPropertyAttribute>().Any());

// Should return 1 but returns 0
var extensionMethodCallCount = type.GetProperties()
    .Count(property =>
        property.GetCustomAttributes(true).OfType<DummyPropertyAttribute>().Any());

Please let me know if this is not the good place to report this problem.

BTW I found this issue which seems more or less related #17180

@pinkfloydx33
Copy link

pinkfloydx33 commented Jul 11, 2019

It's been documented that the inherits parameter does not work for properties or events and that you need to use Attribute.GetCustomAttributes. This probably explains this difference if you were to look at the underlying implementations of the two calls.

This method ignores the inherit parameter for
properties and events. To search the inheritance
chain for attributes on properties and events, use
the appropriate overloads of the
Attribute.GetCustomAttributes method.

MSDN

@Evangelink
Copy link
Member Author

@pinkfloydx33 I have to admit I didn't read MSDN, sorry about that!

I am still not sure to understand why it's working when used like CustomAttributeExtensions.GetCustomAttributes(property, true). If it's really ignoring the inherit parameter for PropertyInfo it should behave the same when not used as extension method, shouldn't it?

@pinkfloydx33
Copy link

I'm pretty sure that you're not calling the same method in both versions of your code. PropertyInfo (via MemberInfo) has an instance method GetCustomAttributes. That is what you're calling with the latter form whereas you're explicitly invoking the extension method (which calls Attribute.GetCustomAttributes) in the former.

@msftgits msftgits transferred this issue from dotnet/corefx Feb 1, 2020
@msftgits msftgits added this to the Future milestone Feb 1, 2020
@maryamariyan maryamariyan added the untriaged New issue has not been triaged by the area owner label Feb 23, 2020
@GrabYourPitchforks
Copy link
Member

A little history behind this. Some frameworks didn't expose the instance method MemberInfo.GetCustomAttributes(bool), so the extension method was added to account for this missing API. Since the extension method couldn't call MemberInfo.GetCustomAttributes(bool) - it was missing, after all - it had to do the next best thing and call Attribute.GetCustomAttributes(MemberInfo, bool). As mentioned in #30219 (comment), there is a subtle behavioral difference between these two methods. It's unfortunate that the behavioral difference is there since it could cause behavioral differences depending on what target framework you compiled against, but the behavior is established by now and I don't see us changing it at this time as it could break people.

@GrabYourPitchforks GrabYourPitchforks removed the untriaged New issue has not been triaged by the area owner label Mar 12, 2020
@ghost ghost locked as resolved and limited conversation to collaborators Dec 12, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area-System.Reflection question Answer questions and provide assistance, not an issue with source code or documentation.
Projects
None yet
Development

No branches or pull requests

5 participants