Почему это свойство Getter является виртуальным?

Имея странную проблему с некоторым кодом С# - метод Getter для свойства отображается как виртуальный, если явно не отмечен.

Проблема проявляется с свойством DbKey в этом классе (полный код):

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);
    }
}

Когда я использую отражение для проверки свойства DbKey, я получаю следующий (неожиданный) результат:

Type t = typeof(ProcessingContextKey);
PropertyInfo p = t.GetProperty("DbKey");
bool virtualGetter = p.GetGetMethod(true).IsVirtual; // True!
bool virtualSetter = p.GetSetMethod(true).IsVirtual; // False

Почему virtualGetter получает значение True? Я ожидал false, учитывая, что свойство не является абстрактным и виртуальным.

Для полноты - и для отдаленной возможности они актуальны, вот объявления для BusinessEntityKey, IProcessingContextKey и IBusinessEntityKey:

public abstract class BusinessEntityKey : IBusinessEntityKey
{
    public abstract Type GetEntityType();
}

public interface IProcessingContextKey : IBusinessEntityKey 
{
    int DbKey { get; }
}

public interface IBusinessEntityKey
{
    Type GetEntityType();
}

Заранее благодарим за помощь.

Разъяснение - почему это имеет значение для меня?

Мы используем NHibernate и отслеживаем некоторые проблемы с ленивой загрузкой свойств, которые были только наполовину переопределены - виртуальный приемник, но частный сеттер. После их исправления мы добавили Unit test, чтобы поймать любые другие места, где это могло произойти:

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)));
}

Этот Unit test терпел неудачу в свойстве DbKey, упомянутом выше, и я не понимал, почему.

Ответ 1

Он виртуальный, поскольку он реализует метод интерфейса. Методы реализации интерфейса всегда являются виртуальными по отношению к CLR.

Ответ 2

Получатель свойства DbKey является виртуальным в IL, потому что он находится в интерфейсе. Сеттер не является виртуальным, потому что он не является частью интерфейса, а является частью конкретного класса.

ECMA-335: общая языковая инфраструктура В разделе 8.9.4 указано, что:

Интерфейсы могут иметь статические или виртуальные методы, но не должны иметь методов экземпляров.

Поэтому получатель, определенный вашим интерфейсом, будет отмечен виртуальным при реализации в производном классе.

Ответ 3

Ссылка в документацию, которая объясняет, что свойства, которые реализуют интерфейсы, всегда отмечены как виртуальные. Чтобы убедиться, что он действительно виртуальный (поскольку он реализует интерфейс), вам также необходимо проверить, не IsFinal.