我想自动化一些测试来检查程序员编写高效算法的能力。在此示例中,算法将在int数组中执行简单的二进制搜索。
public class ComplexityPractice
{
public bool BinarySearch(int [] sortedArray, int value)
{
// to be implement
}
}
注意:此代码由受限域中的反射加载。
实现此方法的简单方法当然是来自.NET库的Array.BinarySearch(sortedArray, value)
。但我的目标是检查程序员自己生成代码的能力,所以问题是:
如何阻止程序员使用Array类中的函数?
答案 0 :(得分:-1)
方法1:
检查代码是否有效,然后测试它是否包含不允许的方法调用,但是您必须忽略字符串文字。
但是,如果Reflection
可用,则不会阻止用户按名称调用方法。
bool validCode = true;
string[] unallowedMethods = new string[]
{
"Array.BinarySearch",
...
};
string sourceCode = ...;
ICodeCompiler codeCompiler = ...;
CompilerResults results = codeCompiler.CompileAssemblyFromSource(parameters, sourceCode);
validCode = result.Errors.Count == 0;
if (validCode)
foreach (method in unallowedMethods)
if (sourceCode.Contains(method)))
//improve this by checking if occurrence is not a string literal in program
{
validCode = false;
break;
}
方法2:
测试一个方法是否使用Mono Cecil调用另一个方法:
Take a look at this answer
static class MethodDefinitionExtensions
{
public static bool CallsMethod(this MethodDefinition caller,
MethodDefinition callee)
{
return caller.Body.Instructions.Any(x =>
x.OpCode == OpCodes.Call && x.Operand == callee);
}
}
class Program
{
private static AssemblyDefinition _assembly = AssemblyDefinition.ReadAssembly(
System.Reflection.Assembly.GetExecutingAssembly().Location);
private static void Method1()
{
Method2();
}
private static void Method2()
{
Method1();
Method3();
}
private static void Method3()
{
Method1();
}
private static IEnumerable<MethodDefinition> GetMethodsCalled(
MethodDefinition caller)
{
return caller.Body.Instructions
.Where(x => x.OpCode == OpCodes.Call)
.Select(x => (MethodDefinition)x.Operand);
}
private static MethodDefinition GetMethod(string name)
{
TypeDefinition programType = _assembly.MainModule.Types
.FirstOrDefault(x => x.Name == "Program");
return programType.Methods.First(x => x.Name == name);
}
public static void Main(string[] args)
{
MethodDefinition method1 = GetMethod("Method1");
MethodDefinition method2 = GetMethod("Method2");
MethodDefinition method3 = GetMethod("Method3");
Debug.Assert(method1.CallsMethod(method3) == false);
Debug.Assert(method1.CallsMethod(method2) == true);
Debug.Assert(method3.CallsMethod(method1) == true);
Debug.Assert(GetMethodsCalled(method2).SequenceEqual(
new List<MethodDefinition> { method1, method3 }));
}
}
答案 1 :(得分:-1)
我会考虑使用面向方面编程。
具体来说,我会结帐PostSharp。
PostSharp提供方法边界,允许您在输入方法之前取消方法的执行。
以下是一个例子:
•OnEntry - 在执行方法体之前
•OnExit - 即使出现错误
,也始终在方法执行时调用•OnSuccess - 仅在方法执行完毕且没有异常时调用
•OnException - 仅在方法由于未处理的异常而停止执行时调用
http://www.postsharp.net/blog/post/Day-4-OnMethodBoundaryAspect