Почему это свойство Getter виртуальное? - PullRequest
11 голосов
/ 26 ноября 2008

Возникла странная проблема с некоторым кодом C # - метод 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? Я ожидал ложного, учитывая, что свойство не является ни abstract , ни virtual .

Для полноты - и для удаленной возможности они актуальны, вот декларации для 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 и отследили некоторые проблемы с отложенной загрузкой до свойств, которые были только наполовину переопределенными - виртуальный получатель, но частный установщик. После исправления мы добавили юнит-тест, чтобы поймать другие места, где это может произойти:

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

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

Ответы [ 3 ]

21 голосов
/ 26 ноября 2008

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

6 голосов
/ 26 ноября 2008

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

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

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

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

5 голосов
/ 26 ноября 2008

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...