Порт N Задать запрос CQLINQ на C# LINQ
Можно ли использовать для переноса запроса CQLinq на простой запрос C# LINQ?
Я создаю инструмент анализа кода с использованием API NDepend, и я хотел бы использовать запросы 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. Кто-нибудь может показать мне пример использования?
Спасибо!
1 ответ
Действительно, CQLinq предлагает ряд удобных методов расширения, определенных в пространстве имен NDepend.Reserved.CQLinq. Эти методы расширения получают специальную обработку во время посткомпиляции CQLinq, и pers per se недоступны в C#.
Когда вы пишете в запросе CQLinq: t.Implement("System.IDisposable".AllowNoMatch())
... разрешены специальные методы расширения ExtensionMethodsCQLinqDependency.Implement(). На этапе CQLinq после C#-компиляции / предварительного выполнения попытайтесь разрешить тип, указанный в виде строки ("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, выполнить ее и использовать результат. Пример использования доступен в коде запроса OSS Power Tools с помощью 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();
}