2013-05-13 3 views
0

Я работаю над большим проектом, в котором базовый класс имеет тысячи классов, полученных из него (на них работают несколько разработчиков). Ожидается, что каждый класс переопределит набор методов. Сначала я создал эти тысячи файлов классов с шаблоном кода, который соответствует приемлемому шаблону. Теперь я пишу модульные тесты, чтобы разработчики не отклонялись от этого шаблона. Вот пример сгенерированный класс:Проверка кода против шаблонов шаблонов с использованием отражения

// 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); 
    } 
} 

В модульных тестов, я был в состоянии проверить следующее с помощью отражения:

  • Класс происходит от [BaseClass] и не реализует никаких интерфейсов.
  • Название класса соответствует образцу.
  • Блокировка не отфильтрована.
  • Никаких других блоков блокировки не было добавлено.
  • Поля или свойства уровня класса не объявлены.
  • Все переменные типа значения метода были инициализированы вручную после объявления.
  • Никакие другие методы не были добавлены к производным классам.

выше легко достигается с помощью отражения, но я борюсь с утверждающим следующим списком:

  • Улова блок повторно бросает пойманное скорее исключение, чем оборачивать его или бросать некоторые другие исключения.
  • Линия [return (result);] в конце не была изменена, и никакие другие [return (whatever);] звонки были добавлены. Не знаю, как этого добиться.
  • Убедитесь, что все ссылочные типы, реализующие IDisposable, были удалены.
  • Убедитесь, что все ссылочные типы типа [System .__ ComObject] были вручную удалены и установлены в [null] в блоке finally.

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

Любые советы будут оценены.

+3

Просто подумайте: если методы * need * будут переопределены, почему они являются «виртуальными», а не «абстрактными»? –

+0

Исправлено. Typo, так как я писал пример в редакторе SO. –

ответ

6

Некоторые мысли:

  1. Если методы должны быть переопределены, почему они virtual вместо abstract?
  2. Код, который не следует изменять, не относится к производному классу. Он принадлежит базовому классу.
  3. catch { throw; } бесполезно. Убери это.
  4. Возвращение логического значения из метода void вызывает ошибку компилятора.
  5. Установка локальных переменных на null бесполезна.
  6. Не все ссылочные типы реализуются IDisposable.

В целом: Большинство ваших требований, по-видимому, не имеют значения для бизнеса.

  • Зачем запрещать реализацию интерфейса?
  • Зачем запрещать объявление других методов?
  • Почему запрещается catch оговорки?
  • т.д.

Вы должны действительно думать о том, что ваши реальные потребности бизнеса являются и моделировать классы после них. Если классы должны выполнить определенный контракт, смоделируйте этот контракт. Оставьте реализацию реализатору.


О актуальных вопросов, поднятых:
Вы не можете использовать отражение здесь. Вы можете либо проанализировать исходный код, либо код IL скомпилированной сборки.
Оба варианта довольно сложны и, скорее всего, невозможно достичь в течение ограниченного времени. Я уверен, что для исправления архитектуры потребуется меньше времени, чем реализация одного из этих параметров.

+1

+ зачем иметь до 100 миллионов имен классов? :) –

+0

Я набрал быстрый пример, чтобы были ошибки. Виртуальный фиксированный. Блок захвата удален. Тип возврата исправлен. Разумеется, это применимо там, где оно применяется. Двигаясь дальше, этот проект очень большой и неуклюжий, и у нас нет времени или бюджета, чтобы вмешиваться в архитектуру. Эти производные классы имеют ОЧЕНЬ узкую цель, и я должен обеспечить ее соответствие этим стандартам. Ваш ответ не затрагивает ни одного из моих вопросов. –

+0

@ RaheelKhan: Добавлен явный ответ на ваши вопросы. –

0

Хотя я уверен, что у вас есть очень веская причина для таких жестких требований ... вы считали, что вместо этого вы решили передать Lambda's/Delegates/Action в тестовую функцию?

Невозможно решить все, но более логично дать вам некоторые из поведений, которые вы хотите (например, не можете вернуться, не можете иметь переменные уровня класса, не можете писать код нигде, кроме указанных).

Самая большая проблема с этим была бы захвачена переменными ... но для этого могут быть работы.

Пример кода:

//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 
    } 

Не знаю, если это будет работать, но это только мысль. О, и, как мысль, это не тщательная или проверенная - я бы ожидал, что вы ее решите резко.

+0

Спасибо. Возможно, вы неправильно поняли этот сценарий, если я ничего не пропустил. Скелет функции генерируется для множества классов, а отдельные разработчики затем заполняют их. В качестве примера, '[ComObject com = null;]' не является частью шаблона. Поэтому я не уверен, как ваш подход подходит здесь. –

+0

«Поэтому я не уверен, как ваш подход подходит здесь». Вместо того, чтобы пытаться применять шаблон, настаивая на том, что люди следуют произвольным правилам, вы можете использовать встроенные функции языка, которые будут применять эти ограничения для вас. Объект Com может быть объявлен в логической лямбда, созданной в функции создания аргумента, переданной как аргумент и т. Д. – NPSF3000

+0

Хм ... Можете ли вы посоветовать мне, как использовать эти языковые функции для обеспечения соблюдения таких правил. –

2

Здесь вы можете попытаться использовать Roslyn CTP, если полностью автоматизированный анализ кода - это то, что вам действительно нужно. Он имеет более продвинутый анализ синтаксиса и семантики, чем отражение. Но все еще много работы. Работая непосредственно с разработчиками, а не с их кодом, подготовкой шаблонов, рекомендации могут быть более эффективными по времени.

+0

Спасибо. Это выглядит очень интересно. Я изучаю CodeDom, но вполне может пойти с Roslyn после некоторых исследований в нем. Да, это большая работа, и хотя у нас уже есть правила создания и разработки шаблонов, проверка тысяч классов на тонкие отклонения шаблонов - это кошмар, если у вас нет уверенности в автоматическом анализе. Оттуда логическая проверка наряду с тестированием занимает сравнительно мало времени. –

 Смежные вопросы

  • Нет связанных вопросов^_^