Ich habe den folgenden NUnit-Test gemacht, die Reflexion, die Umsetzung zu überprüfen verwendet. Hoffentlich können Sie sich nach Bedarf anpassen.
Ich vermute, dass es überladene Methoden nicht gut behandelt, aber es ist ausreichend für das, was ich will.
(Kommentare willkommen)
/// <summary>
/// Use on a (possibly abstract) method or property to indicate that all subclasses must provide their own implementation.
///
/// This is stronger than just abstract, as when you have
///
/// A { public abstract void Method()}
/// B: A { public override void Method(){} }
/// C: B {}
///
/// C will be marked as an error
/// </summary>
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Method)]
public class AllSubclassesMustOverrideAttribute : Attribute
{
}
[TestFixture]
public class AllSubclassesMustOverrideAttributeTest
{
[Test]
public void SubclassesOverride()
{
var failingClasses = new List<string>();
foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
{
try
{
foreach (var type in assembly.GetTypes())
{
foreach (var methodInfo in type.GetMethods().Where(m => m.HasAttributeOfType<AllSubclassesMustOverrideAttribute>()))
{
foreach (var subClass in type.ThisTypeAndSubClasses())
{
var subclassMethod = subClass.GetMethod(methodInfo.Name);
if (subclassMethod.DeclaringType != subClass)
{
failingClasses.Add(string.Format("Class {0} has no override for method {1}", subClass.FullName, methodInfo.Name));
}
}
}
foreach (var propertyInfo in type.GetProperties().Where(p => p.HasAttributeOfType<AllSubclassesMustOverrideAttribute>()))
{
foreach (var subClass in type.ThisTypeAndSubClasses())
{
var subclassProperty = subClass.GetProperty(propertyInfo.Name);
if (subclassProperty.DeclaringType != subClass)
{
failingClasses.Add(string.Format("Class {0} has no override for property {1}", subClass.FullName, propertyInfo.Name));
}
}
}
}
}
catch (ReflectionTypeLoadException)
{
// This will happen sometimes when running the tests in the NUnit runner. Ignore.
}
}
if (failingClasses.Any())
{
Assert.Fail(string.Join("\n", failingClasses));
}
}
}
Es verwendet die folgenden Erweiterungsmethoden
public static bool HasAttributeOfType<T>(this ICustomAttributeProvider provider)
{
return provider.GetCustomAttributes(typeof(T), false).Length > 0;
}
public static IEnumerable<Type> ThisTypeAndSubClasses(this Type startingType)
{
var types = new List<Type>();
foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
{
try
{
foreach (var type in assembly.GetTypes())
{
if (startingType.IsAssignableFrom(type))
{
types.Add(type);
}
}
}
catch (ReflectionTypeLoadException)
{
// Some assembly types are unable to be loaded when running as nunit tests.
// Move on to the next assembly
}
}
return types;
}
Solange einige konkrete Klasse in der Vererbungsbaum hat die abstrakte Methode implementiert, warum sollten Sie, wenn ein Kind kümmern von dieser konkreten Klasse hängt von der Umsetzung ihrer Eltern ab? –
Ich bin zu spät zur Party, aber ich habe das gleiche Problem.Ich hätte gerne ein 'private abstract'-Qualifikationsmerkmal, das jede abgeleitete Klasse dazu zwingt, die Funktion zu implementieren, aber verhindert, dass der Code der Klasse implizit auf die Implementierung einer Elternklasse zurückfällt. 'Clone()' ist ein gutes Beispiel. Mein Fall ist mehr wie 'ToString()'. Etwas Generisches, aber verschieden pro Klasse. –
Eigentlich muss das öfter vorkommen (oder mir fehlt etwas). –