最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

c# - Attribute.IsDefined() isn't working for my custom MemberInfo type - Stack Overflow

programmeradmin1浏览0评论

The short of it is that I got tired of dealing with properties and fields separately. I made a VariableInfo strategy pattern to handle both without having to know what type it is. You feed the context a FieldInfo or a PropertyInfo and it makes a VariableInfo out of it. I've also made VariableInfo extend MemberInfo. There are extensions for pulling a type's fields and properties and returning all of them as VariableInfo objects. Here is a part of the class definition (check this github repo for complete definition of all classes I describe here)

public class VariableInfo : MemberInfo
{
    private InfoParent variable;
    public VariableInfo(PropertyInfo pi) 
    {
        variable = new VariableProperty(pi);
    }
    public VariableInfo(FieldInfo fi)
    {
        variable = new VariableField(fi);
    }
    ...
}

The issue I have is using Attribute.IsDefined(MemberInfo element) with a VariableInfo object. It works for fields, but not properties. When you jump a couple levels into the BCL source code you can see the point at which it fails -

return element.MemberType switch
 {
     MemberTypes.Property => InternalIsDefined((PropertyInfo)element, attributeType, inherit),
     MemberTypes.Event => InternalIsDefined((EventInfo)element, attributeType, inherit),
     _ => element.IsDefined(attributeType, inherit),
 };

It's the casting from the MemberInfo element variable to a PropertyInfo version of it. System.InvalidCastException: 'Unable to cast object of type 'System.Reflection.VariableInfo' to type 'System.Reflection.PropertyInfo'.'The fields go down a different path, so thats why those work.

I have defined implicit/explicit operator overrides so I can cast the objects from VariableInfo to PropertyInfo back and forth as much as I want in my code.

public static explicit operator PropertyInfo(VariableInfo a)
{
    return a.variable.mi as PropertyInfo;
}
public static explicit operator FieldInfo(VariableInfo a)
{
    return a.variable.mi as FieldInfo;
}

public static implicit operator VariableInfo(PropertyInfo a)
{
    return new VariableInfo(a);
}
public static implicit operator VariableInfo(FieldInfo a)
{
    return new VariableInfo(a);
}

This works fine in my test code:

PropertyInfo asPropInfo = (PropertyInfo)VariableInfoObjectContainingAProperty; 

but the internals of Attribute.IsDefined can't cast using my explicit overloads. Anyone know why this fails or how to fix it?

Using framework 4.7.2

The short of it is that I got tired of dealing with properties and fields separately. I made a VariableInfo strategy pattern to handle both without having to know what type it is. You feed the context a FieldInfo or a PropertyInfo and it makes a VariableInfo out of it. I've also made VariableInfo extend MemberInfo. There are extensions for pulling a type's fields and properties and returning all of them as VariableInfo objects. Here is a part of the class definition (check this github repo for complete definition of all classes I describe here)

public class VariableInfo : MemberInfo
{
    private InfoParent variable;
    public VariableInfo(PropertyInfo pi) 
    {
        variable = new VariableProperty(pi);
    }
    public VariableInfo(FieldInfo fi)
    {
        variable = new VariableField(fi);
    }
    ...
}

The issue I have is using Attribute.IsDefined(MemberInfo element) with a VariableInfo object. It works for fields, but not properties. When you jump a couple levels into the BCL source code you can see the point at which it fails -

return element.MemberType switch
 {
     MemberTypes.Property => InternalIsDefined((PropertyInfo)element, attributeType, inherit),
     MemberTypes.Event => InternalIsDefined((EventInfo)element, attributeType, inherit),
     _ => element.IsDefined(attributeType, inherit),
 };

It's the casting from the MemberInfo element variable to a PropertyInfo version of it. System.InvalidCastException: 'Unable to cast object of type 'System.Reflection.VariableInfo' to type 'System.Reflection.PropertyInfo'.'The fields go down a different path, so thats why those work.

I have defined implicit/explicit operator overrides so I can cast the objects from VariableInfo to PropertyInfo back and forth as much as I want in my code.

public static explicit operator PropertyInfo(VariableInfo a)
{
    return a.variable.mi as PropertyInfo;
}
public static explicit operator FieldInfo(VariableInfo a)
{
    return a.variable.mi as FieldInfo;
}

public static implicit operator VariableInfo(PropertyInfo a)
{
    return new VariableInfo(a);
}
public static implicit operator VariableInfo(FieldInfo a)
{
    return new VariableInfo(a);
}

This works fine in my test code:

PropertyInfo asPropInfo = (PropertyInfo)VariableInfoObjectContainingAProperty; 

but the internals of Attribute.IsDefined can't cast using my explicit overloads. Anyone know why this fails or how to fix it?

Using framework 4.7.2

Share Improve this question edited Mar 18 at 16:44 A person asked Mar 15 at 2:51 A personA person 798 bronze badges 3
  • 1 Please share a minimal reproducible example. – mjwills Commented Mar 15 at 8:37
  • this requires you to have 4 classes worth of code to abstract out propertyinfo and fieldinfo to test it out, so I put the code on git and linked the git. everything up to and including the try/catch is the minimal reproducible example. after the try/catch in the main method is an example of how you could use the structure in case someone stumbles upon it in the future and thinks it might help them – A person Commented Mar 15 at 18:42
  • Your class needs to extend either PropertyInfo or FieldInfo to be usable as those types, which sadly is hard to achieve. Since you are on .NET Framework, you could theoretically use proxying to have a single instance that is castable to either based on implementation details, but it is another can of worms. – IS4 Commented Mar 23 at 21:14
Add a comment  | 

1 Answer 1

Reset to default 1

For why there is InvalidCastException despite your explicit custom conversion - you can have a look at this question. Basically your explicit/implicit operator overloads are compile time for YOUR code. The casting in the BCL code you dug up cannot apply/does not know about your custom operators - it does a runtime cast - you get the exception.

For how to fix this - going from what the BCL code check does

return element.MemberType switch
 {
     MemberTypes.Property => InternalIsDefined((PropertyInfo)element, attributeType, inherit),
     MemberTypes.Event => InternalIsDefined((EventInfo)element, attributeType, inherit),
     _ => element.IsDefined(attributeType, inherit),
 };

and your implementation of MemberType which just relays to the captured MemberInfo:

public override MemberTypes MemberType => variable.MemberType;

You need to make use of MemberTypes.Custom which your VariableInfo type really is (it is not PropertyInfo or FieldInfo):

public override MemberTypes MemberType => MemberTypes.Custom;

Then it would fall back to your IsDefined implementation you are happy with:

_ => element.IsDefined(attributeType, inherit),
发布评论

评论列表(0)

  1. 暂无评论