Перенести запрос NDepend CQLINQ на c# LINQ

Можно ли использовать для переноса запроса CQLinq на простой запрос C# LINQ?

Я создаю инструмент анализатора кода, используя NDepend API, и я хотел бы использовать запросы CQLinq.

Некоторые из них легко портировать. Например,

from m in Methods
where m.ILCyclomaticComplexity > 10 
orderby m.ILCyclomaticComplexity descending
select new { m }

легко портируется на

using NDepend.CodeModel;
using NDepend.CodeQuery;

public List<IMethod> GetUnitTestFromType(ICodeBase codeBase)
{
    var complexMethods = (from m in codeBase.Application.Methods
                      where m.ILCyclomaticComplexity > 10
                      orderby m.ILCyclomaticComplexity descending
                      select m).ToList();
    return complexMethods;
} 

Но я хотел бы использовать более мощные методы CQLinq, т.е. AllowNoMatch()

from t in codeBase.Application.Types
where t.Implement("System.IDisposable".AllowNoMatch())
select t;

На самом деле было бы здорово напрямую использовать запрос CQLinq. Как?

Я вижу, что существует пространство имен NDepend.CodeQuery с такими методами, как CreateQuery, Compile и Execute. Может ли кто-нибудь показать мне пример использования?

Спасибо!


person Kaikus    schedule 05.10.2013    source источник


Ответы (1)


Действительно, CQLinq предлагает ряд удобных методов расширения, определенных в пространстве имен NDepend.Reserved.CQLinq. Эти методы расширения получают специальную обработку во время пост-компиляции CQLinq и сами по себе недоступны в C#.

Когда вы пишете запрос CQLinq: t.Implement("System.IDisposable".AllowNoMatch())

... специальный ExtensionMethodsCQLinqDependency. Решены методы расширения Implement(). Шаг CQLinq после компиляции/перед выполнением CQLinq пытается разрешить тип, указанный в виде строки ( "System.IDisposable".AllowNoMatch() ), один раз перед выполнением и выводит предикат на IType.

  • Если тип с полным именем "System.IDisposable" не найден, всегда возвращается false.
  • Если найден тип с полным именем "System.IDisposable", возвращает true. для типов, реализующих его.

В документации ExtensionMethodsCQLinqDependency.Implement () указано, что этот метод может быть вызван только в ICQLinqExecutionContext, иначе вместо него должен быть вызван метод NDepend.CodeModel.IType.NDepend.CodeModel.IType.Implement.

Следовательно, используя NDepend.API, вы должны самостоятельно выполнить работу после компиляции CQLinq, но это довольно быстро:

var iDisposable = codebase.Types.SingleOrDefault(t.FullName == "System.IDisposable");
if(iDisposable == null) {
  return new IType[0];
}
return from t in codeBase.Application.Types
       where t.Implement(iDisposable)
       select t;

Я вижу, что существует пространство имен NDepend.CodeQuery с такими методами, как CreateQuery, Compile и Execute. Кто-нибудь может показать мне пример использования?

Действительно, с помощью NDepend.API вы можете скомпилировать строку запроса CQLinq, выполнить ее и использовать результат. Пример использования доступен в Power Tools OSS Код запроса с помощью CQLinq, $NDependRedistributable$\NDepend.PowerTools\CodeQueryConsole\CodeQueryConsolePowerTool.cs

     var codeBase = analysisResult.CodeBase;
     Func<string, IQueryCompiled> compileQueryProc = queryString => queryString.Compile( codeBase);

     // ... but if we can get a compareContext, then compile and execute the query against the compareContext
     ICompareContext compareContext;
     if (ProjectAnalysisUtils.TryGetCompareContextDefinedByBaseline(analysisResult, out compareContext)) {
        Debug.Assert(compareContext != null);
        compileQueryProc = queryString => queryString.Compile(compareContext);
     }

...
       IQueryCompiled queryCompiled;
       using (var queryEditSession = new QueryEditSession(queriesPreviouslyEdited)) {
           var queryString = queryEditSession.GetQueryString();
COMPILE_QUERY:
           Console.BackgroundColor = ConsoleColor.Black;
           Console.ForegroundColor = ConsoleColor.White;
           if (queryString == null) { break; }

           // Try compile query
           queryCompiled = compileQueryProc(queryString);
           var queryCompiledError = queryCompiled.QueryCompiledError;
           if (queryCompiledError != null) {
              queryString = queryEditSession.ShowCompilatioErrorsAndThenGetQueryString(queryCompiledError);
              goto COMPILE_QUERY;
           }
        }

        // Execute query compiled
        var queryCompiledSuccess = queryCompiled.QueryCompiledSuccess;
        Debug.Assert(queryCompiledSuccess != null);
        var result = queryCompiledSuccess.Execute();
        if (result.Status != QueryExecutionStatus.Success) {
           var exception = result.Exception;
           // The error must be an Exception thrown by the query, since we don't use the Execute(...) overload with time-out!
           Debug.Assert(exception != null);
           DisplayQueryThrowAnException(exception);
           continue;
        }

        QueryExecutionResultDisplayer.Go(result.SuccessResult);
        Console.WriteLine();
     }
person Patrick from NDepend team    schedule 07.10.2013
comment
Спасибо! Вот отправная точка, которая мне нужна, метод расширения для строк из пространства имен NDepend.CodeQuery: «Compile»! ndepend.com/api/< /а> - person Kaikus; 07.10.2013