私は実装を確認するためにリフレクションを使用して、次のNUnitのテストを行いました。うまくいけば、あなたは必要に応じて適応することができます。
私はそれがオーバーロードされたメソッドをうまく扱えないと思っていますが、私が望むものには十分です。
(コメント歓迎)
/// <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));
}
}
}
それは限り、継承ツリー内のいくつかの具体的なクラスは、抽象メソッド、子供の場合は、なぜあなたは気になりを実施しているとして、次の拡張メソッド
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;
}
を使用していますその具体的なクラスの親の実装に依存していますか? –
私はパーティーに遅れていますが、同じ問題があります。私は、すべての派生クラスに関数を実装させるが、クラスのコードは暗黙的に親クラスの実装に戻ってしまうのを防ぐ 'private abstract'修飾子が必要です。 'Clone()'は良い例です。私の場合は 'ToString()'のようなものです。ジェネリックだがクラスごとに異なるもの。 –
実際には、これはより頻繁に発生する必要があります(または何かが欠落しています)。 –