Здесь нам придется иметь дело с методами метода свойства, а не с самим свойством, потому что методы get / set свойства на самом деле переопределяются, а не само свойство. Я буду использовать метод get, поскольку у вас никогда не должно быть свойства без него, хотя полное решение должно проверять отсутствие свойства.
Глядя на IL, выдаваемый в ряде случаев, метод 'get' базового свойства будет иметь токены метаданных (это от компилятора C #; другие могут не испускать hidebysig
в зависимости от их метода, скрывающего семантику в этом случае метод будет скрыт по имени):
non-virtual : .method public hidebysig specialname instance
virtual : .method public hidebysig specialname newslot virtual instance
Производный будет иметь следующие токены:
override : .method public hidebysig specialname virtual instance
new : .method public hidebysig specialname instance
new virtual : .method public hidebysig specialname newslot virtual instance
Таким образом, мы можем видеть из этого, что невозможно просто определить из токенов метаданных метода, является ли он new
, потому что не виртуальный базовый метод имеет те же токены, что и не виртуальный new
метод, и метод виртуальной базы имеет те же маркеры, что и метод new virtual
.
То, что мы можем сказать, заключается в том, что если метод имеет токен virtual
, но не токен newslot
, то он переопределяет базовый метод, а не затеняет его, т. Е.
var prop = typeof(ChildClass).GetProperty("TempProperty");
var getMethod = prop.GetGetMethod();
if ((getMethod.Attributes & MethodAttributes.Virtual) != 0 &&
(getMethod.Attributes & MethodAttributes.NewSlot) == 0)
{
// the property's 'get' method is an override
}
Предполагая, таким образом, что мы находим, что метод 'get' не является переопределением, мы хотим знать, существует ли свойство в базовом классе, для которого он выполняет теневое копирование. Проблема заключается в том, что поскольку метод находится в другом слоте таблицы методов, он на самом деле не имеет прямого отношения к методу, который он отслеживает. Итак, что мы на самом деле говорим: «есть ли у базового типа какой-либо метод, отвечающий критериям теневого копирования», который зависит от того, является ли метод hidebysig
или скрытым по имени.
Для первого нам нужно проверить, есть ли у базового класса какой-либо метод, который точно соответствует сигнатуре, тогда как для последнего нам нужно проверить, есть ли у него какой-либо метод с тем же именем, поэтому продолжаем код сверху:
else
{
if (getMethod.IsHideBySig)
{
var flags = getMethod.IsPublic ? BindingFlags.Public : BindingFlags.NonPublic;
flags |= getMethod.IsStatic ? BindingFlags.Static : BindingFlags.Instance;
var paramTypes = getMethod.GetParameters().Select(p => p.ParameterType).ToArray();
if (getMethod.DeclaringType.BaseType.GetMethod(getMethod.Name, flags, null, paramTypes, null) != null)
{
// the property's 'get' method shadows by signature
}
}
else
{
var flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance;
if (getMethod.DeclaringType.BaseType.GetMethods(flags).Any(m => m.Name == getMethod.Name))
{
// the property's 'get' method shadows by name
}
}
}
Я думаю, что это большая часть пути, но я все еще не думаю, что это совершенно правильно. Для начала я не совсем знаком с сокрытием по имени, поскольку C # не поддерживает его, и это почти все, что я использую, поэтому я могу ошибаться в коде, который указывает, что метод экземпляра может скрывать статический метод. Я также не знаю о проблеме чувствительности к регистру (например, в VB мог бы метод с именем Foo
затенять метод с именем foo
, если они оба имели одинаковую сигнатуру и оба были hidebysig
- в C # ответ - нет, но если в VB ответ положительный, то это означает, что ответ на этот вопрос фактически недетерминирован).
Ну, я не уверен, насколько все это поможет, кроме как проиллюстрировать, что это на самом деле гораздо более сложная проблема, чем я думал (или я пропустил что-то действительно очевидное, в таком случае мне бы хотелось знать!). Но, надеюсь, у него достаточно контента, чтобы помочь вам достичь того, что вы пытаетесь сделать.