Verifying code against template patterns using reflection

感情迁移 提交于 2019-12-25 03:41:34

问题


I am working on a large project where a base class has thousands of classes derived from it (multiple developers are working on them). Each class is expected to override a set of methods. I first generated these thousands of class files with a code template that conforms to an acceptable pattern. I am now writing unit tests to ensure that developers have not deviated from this pattern. Here is a sample generated class:

// Base class.
public abstract partial class BaseClass
{
    protected abstract bool OnTest ();
}

// Derived class. DO NOT CHANGE THE CLASS NAME!
public sealed partial class DerivedClass_00000001: BaseClass
{
    /// <summary>
    /// Do not modify the code template in any way.
    /// Write code only in the try and finally blocks in this method.
    /// </summary>
    protected override void OnTest ()
    {
        bool result = false;
        ComObject com = null;
        // Declare ALL value and reference type variables here. NOWHERE ELSE!
        // Variables that would otherwise be narrowly scoped should also be declared here.
        // Initialize all reference types to [null]. [object o;] does not conform. [object o = null;] conforms.
        // Initialize all value types to their default values. [int x;] does not conform. [int x = 0;] conforms.

        try
        {
            com = new ComObject();

            // Process COM objects here.
            // Do NOT return out of this function yourself!
        }
        finally
        {
            // Release all COM objects.
            System.Runtime.InteropServices.Marshal.ReleaseComObject(com);

            // Set all COM objects to [null].
            // The base class will take care of explicit garbage collection.
            com = null;
        }

        return (result);
    }
}

In the unit tests, I have been able to verify the following via reflection:

  • The class derives from [BaseClass] and does not implement any interfaces.
  • The class name conforms to a pattern.
  • The catch block has not been filtered.
  • No other catch blocks have been added.
  • No class level fields or properties have been declared.
  • All method value type variables have been manually initialized upon declaration.
  • No other methods have been added to the derived classes.

The above is easily achieved via reflection but I am struggling with asserting the following list:

  • The catch block re-throws the caught exception rather than wrapping it or throwing some other exception.
  • The [return (result);] line at the end has not been modified and no other [return (whatever);] calls have been added. No idea how to achieve this.
  • Verify that all reference types implementing IDisposable have been disposed.
  • Verify that all reference types of type [System.__ComObject] have been manually de-referenced and set to [null] in the finally block.

I have thought about parsing the source code but I don't like that solution unless absolutely necessary. It is messy and unless I have expression trees, almost impossible to guarantee success.

Any tips would be appreciated.


回答1:


Some thoughts:

  1. If the methods need to be overriden, why are they virtual instead of abstract?
  2. Code that should not be changed doesn't belong in the derived class. It belongs in the base class.
  3. catch { throw; } is useless. Remove it.
  4. Returning a boolean value from a void method causes a compiler error.
  5. Setting local variables to null is useless.
  6. Not all reference types implement IDisposable.

Generally: Most of your requirements seem to have no business value.

  • Why prohibit implementation of an interface?
  • Why prohibit declaration of other methods?
  • Why prohibit catch clauses?
  • etc.

You should really think about what your actual business requirements are and model your classes after them. If the classes need to fulfill a certain contract, model that contract. Leave the implementation to the implementor.


About the actual questions raised:
You can't use reflection here. You can either analyze the original source code or the IL code of the compiled assembly.
Both options are pretty tricky and most likely impossible to achieve within your limited time. I am positive that fixing the architecture would take less time than implementing one of those options.




回答2:


You could try to use Roslyn CTP here if the fully automated code analysis is what you really need. It has more advanced syntax and semantics analysis than reflection does. But it is still a lot of work. Working directly with developers, not with their code, preparing templates, guidelines may be more time efficient.




回答3:


While I'm sure you have a very good reason for such rigid requirements... have you considered passing a Lambda's/Delegates/Action to the Test function instead?

Can't solve everything, but would more logically give you some of the behaviours you want (e.g. can't return, can't have class level variables, can't write code anywhere but specified).

Biggest concern with it would be captured variables... but there may be work arounds for that.

Example Code:

//I'd make a few signatures....
bool OnTest<T1, T2> (Action<ComObject, T1, T2> logic, T1 first, T2 second)
    {
        bool result = false;
        ComObject com = null;

        //no checks needed re parameters
        //Can add reflection tests here if wanted before code is run.

        try
        {
            com = new ComObject();
            //can't return
            logic(com, first,second);
        }
        finally
        {
            // Release all COM objects.
            System.Runtime.InteropServices.Marshal.ReleaseComObject(com);

            // Set all COM objects to [null].
            // The base class will take care of explicit garbage collection.
            com = null;

            //If you want, we can check each argument and if it is disposable dispose.
            if (first is IDisposable  && first != null) ((IDisposable) first).Dispose();
            ...
        }

        return (result);  //can't be changed
    }

No idea if this'll work, but it's just a thought. Oh, and as a thought it's not thorough or tested - I'd expect you to develop it drastically.



来源:https://stackoverflow.com/questions/16524235/verifying-code-against-template-patterns-using-reflection

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!