Having a strange issue with some C# code – the Getter method for a property is showing up as virtual when not explicitly marked.
The problem exhibits with the DbKey property on this class (code in full):
public class ProcessingContextKey : BusinessEntityKey, IProcessingContextKey { public ProcessingContextKey() { // Nothing } public ProcessingContextKey(int dbKey) { this.mDbKey = dbKey; } public int DbKey { get { return this.mDbKey; } set { this.mDbKey = value; } } private int mDbKey; public override Type GetEntityType() { return typeof(IProcessingContextEntity); } }
When I use reflection to inspect the DbKey property, I get the following (unexpected) result:
Type t = typeof(ProcessingContextKey); PropertyInfo p = t.GetProperty('DbKey'); bool virtualGetter = p.GetGetMethod(true).IsVirtual; // True! bool virtualSetter = p.GetSetMethod(true).IsVirtual; // False
Why does virtualGetter get set to True? I expected false, given that the property is neither abstract nor virtual.
For completeness – and for the remote possibilty they are relevant, here are the declarations for BusinessEntityKey, IProcessingContextKey, and IBusinessEntityKey:
public abstract class BusinessEntityKey : IBusinessEntityKey { public abstract Type GetEntityType(); } public interface IProcessingContextKey : IBusinessEntityKey { int DbKey { get; } } public interface IBusinessEntityKey { Type GetEntityType(); }
Thanks in advance for your help.
Clarification – why does this matter to me?
We’re using NHibernate and traced some issues with lazy loading to properties that were only half overridable – virtual getter but private setter. After fixing these up, we added a Unit test to catch any other places where this could occur:
public void RequirePropertiesToBeCompletelyVirtualOrNot() { var properties = typeof(FsisBusinessEntity).Assembly .GetExportedTypes() .Where(type => type.IsClass) .SelectMany( type => type.GetProperties( BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)) .Where(property => property.CanRead && property.CanWrite) .Where(property => property.GetGetMethod(true).IsVirtual != property.GetSetMethod(true).IsVirtual); Assert.That( properties.Count(), Is.EqualTo(0), properties.Aggregate( 'Found : ', (m, p) => m + string.Format('{0}.{1}; ', p.DeclaringType.Name, p.Name))); }
This unit test was failing on the DbKey property mentioned above, and I didn’t understand why.
It’s virtual because it implements an interface method. Interface implementation methods are always virtual as far as the CLR is concerned.