52

Sorry, I am looking up the System.Type type and the PropertyInfo type in the documentation but I can't seem to find the thing I need.

How do I tell if a property (or method or any other member) was declared virtual in its declaring class?

For e.g.

class Cat
{
    public string Name { get; set; }
    public virtual int Age { get; set; }
}

How do I tell if the Age property was declared virtual or not?

Water Cooler v2
  • 32,724
  • 54
  • 166
  • 336

5 Answers5

89

You could use the IsVirtual property:

var isVirtual = typeof(Cat).GetProperty("Age").GetGetMethod().IsVirtual;
Darin Dimitrov
  • 1,023,142
  • 271
  • 3,287
  • 2,928
  • 2
    This will fail if the property being considered is write-only. – cdhowie Nov 22 '10 at 08:25
  • 1
    @cdhowie, yes it will fail. I didn't include error checking in my example. – Darin Dimitrov Nov 22 '10 at 08:38
  • 10
    Another important note. This will fail 100% of the time get or set method if Cat : ICat, and ICat has Age {get;set;}. – aBetterGamer Mar 13 '11 at 02:49
  • 3
    @aBetterGamer It doesn't really fail. There is a difference between a method being virtual and overridable. So it depends what you want to determine. See http://msdn.microsoft.com/en-us/library/system.reflection.methodbase.isvirtual.aspx for more details. – Manfred Dec 31 '11 at 00:11
27

Technically, properties are not virtual -- their accessors are. Try this:

typeof(Cat).GetProperty("Age").GetAccessors()[0].IsVirtual

If you wanted, you could use an extension method like the following to determine if a property is virtual:

public static bool? IsVirtual(this PropertyInfo self)
{
    if (self == null)
        throw new ArgumentNullException("self");

    bool? found = null;

    foreach (MethodInfo method in self.GetAccessors()) {
        if (found.HasValue) {
            if (found.Value != method.IsVirtual)
                return null;
        } else {
            found = method.IsVirtual;
        }
    }

    return found;
}

If it returns null, either the property has no accessors (which should never happen) or all of the property accessors do not have the same virtual status -- at least one is and one is not virtual.

cdhowie
  • 158,093
  • 24
  • 286
  • 300
  • 2
    I used **LINQ** to solve the problem: `var isVirtual = prop.GetType().GetProperties() .Where(x => x.GetAccessors().Any( a => a.IsVirtual ));` – Michael Ceranski Mar 05 '18 at 14:11
  • @MichaelCeranski Note that this does not do the same thing as my code when the accessors have conflicting virtual attributes. – cdhowie Mar 05 '18 at 17:17
3

IsVirtual alone didn't work for me. It was telling me that all my non-virtual non-nullable properties were virtual. I had to use a combination of IsFinal and IsVirtual

Here's what I ended up with:

PropertyInfo[] nonVirtualProperties = myType.GetProperties().Where(x => x.GetAccessors()[0].IsFinal || !x.GetAccessors()[0].IsVirtual).ToArray();

PropertyInfo[] virtualProperties = myType.GetProperties().Where(x => !x.GetAccessors()[0].IsFinal && x.GetAccessors()[0].IsVirtual).ToArray();
Owen
  • 4,229
  • 5
  • 42
  • 50
1

if you are using an generic class of type T then get its properities using the GetProperties method. In this case, I want to bypass any virtual collections that entity framework generates when assign values from by view class to my entity class. The GetAccessors()[0].IsVirtual method will tell me if the property is virtual.

 var propts = typeof(T).GetProperties();

 T model = new T();
   foreach (var viewFieldProperty in propts)
    {

                sourceFieldName = viewFieldProperty.Name;

                Type fieldTypeSource = viewFieldProperty.PropertyType;
                sourceFieldNameType = fieldTypeSource.ToString();

                if(viewFieldProperty.GetAccessors()[0].IsVirtual==false) //bypass virtual collections
                {
                …
                  val = entityObject.GetType().GetProperty(viewFieldProperty.Name).GetValue(entityObject, null);
                  if (val != null) { viewFieldProperty.SetValue(model, val); }
                }
     }
Golden Lion
  • 3,840
  • 2
  • 26
  • 35
0

If a class inherits from an interface all of the properties in the interface are marked as virtual. If you want to check if a property is overridable you need to check that IsFinal is false as well

public static bool IsPropertyOverridable(this PropertyInfo propertyInfo)
{
    return (propertyInfo.IsGetPropertyVirtual() || propertyInfo.IsSetPropertyOverridable());
}

public static bool IsGetPropertyVirtual(this PropertyInfo propertyInfo)
{
    if (false == propertyInfo.CanRead)
    {
        return false;
    }
    return propertyInfo.GetGetMethod(nonPublic: true).IsOverridable();
}

public static bool IsSetPropertyOverridable(this PropertyInfo propertyInfo)
{
    if (false == propertyInfo.CanWrite)
    {
        return false;
    }
    return propertyInfo.GetSetMethod(nonPublic: true).IsOverridable();
}
johnny 5
  • 19,893
  • 50
  • 121
  • 195