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 Answer
Reset to default 1For 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),
PropertyInfo
orFieldInfo
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