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

У меня есть следующий код в модульном тесте

    public bool TestMethodsOf<T, I>()
  {
   var impl = typeof(T);
   var valid = true;

   foreach (var iface in impl.GetInterfaces().Where(i => typeof(I).IsAssignableFrom(i)))
   {

    var members = iface.GetMethods();

    foreach (var member in members)
    {
     Trace.Write("Checking if method " + iface.Name + "." + member.Name + " is virtual...");
     var implMember = impl.GetMethod(member.Name, member.GetParameters().Select(c => c.ParameterType).ToArray());
     if (!implMember.IsVirtual)
     {
      Trace.WriteLine(string.Format("FAILED"));
      valid = false;
      continue;
     }

     Trace.WriteLine(string.Format("OK"));
    }
   }
   return valid;
  }

который я называю

Assert.IsTrue(TestMethodsOf<MyView, IMyView>());

Я хочу убедиться, что все методы из интерфейса объявлены как виртуальные. Причина в том, что я применяю аспект spring.net, и он будет применяться только к виртуальным методам.

Проблема, с которой я сталкиваюсь, заключается в том, что implMember.IsVirtual всегда имеет значение true, даже если они не объявлены как таковые в объявляющем типе.

Что не так с моей логикой TestMethodsOf?

Ваше здоровье


person Sebastian Piu    schedule 25.01.2011    source источник


Ответы (2)


Все методы, объявленные в интерфейсе, помечены как virtual abstract, а все методы, реализующие методы интерфейса в классах, помечены как virtual final, поэтому среда CLR знает, что она не может просто вызывать их напрямую — она должна выполнять поиск в таблице во время выполнения, чтобы вызвать нужный метод. реализация. Реализации интерфейса по-прежнему виртуальные, но вы не можете переопределить их, поскольку они окончательные.

Например, следующее определение C#:

public interface IInterface {
    void Method();
}

public class Class : IInterface {
    public void Method() {}
}

компилируется в следующий IL:

.class public interface abstract IInterface {
    .method public abstract virtual instance void Method() {}
}

.class public Class extends [mscorlib]System.Object implements IInterface {
    .method public specialname rtspecialname instance void .ctor() {}
    .method public virtual final instance void Method() {}
}
person thecoop    schedule 25.01.2011
comment
превосходно! Поэтому я изменил свой код, чтобы проверить IsFinal вместо IsVirtual, и теперь он работает нормально. Спасибо! - person Sebastian Piu; 25.01.2011

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

person Massif    schedule 25.01.2011
comment
Если я попытаюсь переопределить методы в объявляющем типе, я не смогу этого сделать. Кроме того, аспект наследования в этом случае не переопределяет вызовы моих методов, поэтому не определяет их как виртуальные. - person Sebastian Piu; 25.01.2011