Content
NDepend 2.0 has just been released (download it at http://www.NDepend.com). It is a free .NET tool for developers which analyses IL code and produces reports containing numerous code metrics, warnings and diagrams. The 2.0 version provides great enhancements such as an interactive view of your application and a new language dedicated to query and constraint the structure of your code: Code Query Language (CQL).
The purpose of this article is to expose some quantitative and qualitative information about the .NET framework 2.0 obtained from some CQL queries. We'll consider that the .NET 2.0 framework is made of the following 15 assemblies: System.Windows.Forms, System.Web, mscorlib, System, System.Data, System.XML, System.Deployment, System.Web.Services, System.Data.SqlXml, System.Drawing, System.Runtime.Remoting, System.Transactions, System.Messaging, System.Security, System.Drawing.Design
We choose to analyse the .NET framework 2.0 since obviously, every developers know it. However we precise that NDepend 2.0 can be used to analyse any .NET application (i.e any set of assemblies) no matter it is a console, windows form or ASP.NET application and no matter it is written with C# or VB.NET or any other .NET language.
Let's have a first glimpse of the size of each assembly thanks to the following CQL query:
SELECT ASSEMBLIES ORDER BY NbILinstructions DESC, NbNamespaces DESC, NbTypes DESC, NbMethods DESC
| Name |
# IL instructions |
# Namespaces |
# Types |
# Methods |
| System.Windows.Forms |
560331 |
20 |
2214 |
27754 |
| System.Web |
478412 |
24 |
1874 |
22638 |
| mscorlib |
429203 |
53 |
2319 |
21040 |
| System |
357693 |
39 |
1924 |
15095 |
| System.XML |
297142 |
12 |
849 |
10331 |
| System.Data |
291324 |
14 |
860 |
11722 |
| System.Data.SqlXml |
117347 |
10 |
433 |
4520 |
| System.Web.Services |
97166 |
10 |
329 |
2603 |
| System.Drawing |
58669 |
11 |
298 |
3930 |
| System.Runtime.Remoting |
42185 |
8 |
182 |
1419 |
| System.Deployment |
38830 |
8 |
466 |
2094 |
| System.Security |
30752 |
7 |
203 |
1256 |
| System.Transactions |
23726 |
5 |
203 |
1381 |
| System.Messaging |
20586 |
5 |
104 |
966 |
| System.Drawing.Design |
7690 |
3 |
39 |
285 |
| Sum: |
2851056 |
229 |
12297 |
127034 |
| Average: |
190070.4 |
15.3 |
819.8 |
8468.9 |
| Minimum: |
7690 |
3 |
39 |
285 |
| Maximum: |
560331 |
53 |
2319 |
27754 |
| Standard deviation: |
185867.8 |
13.4 |
800.1 |
8851.2 |
| Variance: |
3.454684E+10 |
180.5 |
640139.4 |
7.834298E+07 |
You can see that the CQL syntax is close to the SQL one since it supports the SELECT TOP FROM WHERE ORDER BY pattern. This similarity comes from the fact that NDepend consider metadata and structure of your application as a database. From this point of view, CQL is used to query such database.
Delivered with NDepend 2.0, you'll find the VisualNDepend tool which provides a more intuitive idea of the topology of your application thanks to a treemap view:

VisualNDepend also offers a CQL query editor with intellisense and verbose syntax error description:



Notice also that the NDepend report contains a diagram of assemblies' dependencies:
CQL can help you know where you should focus your energy to enhance the quality of your code. For example you can use the following CQL query to know where your biggest methods are:
SELECT TOP 5 METHODS ORDER BY NbILinstructions DESC
| Name |
# IL instructions |
Full Name |
| MDTransform(Uint32*,Uint32*,Byte*) |
5294 |
System.Security.Cryptography.RIPEMD160Managed.
MDTransform(Uint32*,Uint32*,Byte*) |
| PopulateBrowserElements(IDictionary) |
3596 |
System.Web.Configuration.BrowserCapabilitiesFactory.
PopulateBrowserElements(IDictionary) |
| .cctor() |
2462 |
System.Text.RegularExpressions.RegexCharClass..cctor() |
| .ctor() |
2462 |
System.Text.RegularExpressions.RegexCharClass..ctor() |
ImportAccessorMapping(MemberMapping,FieldModel,
XmlAttributes,String,Type,Boolean,Boolean) |
2344 |
System.Xml.Serialization.XmlReflectionImporter.
ImportAccessorMapping(MemberMapping,FieldModel,
XmlAttributes,String,Type,Boolean,Boolean) |
You might prefer using a threshold:
SELECT METHODS WHERE NbILinstructions > 200 ORDER BY NbILinstructions
(in the case of the .NET framework 2.0, 1107 methods are selected on 127034 methods).
You can transform readily this CQL query into a CQL constraint to ensure that no methods exceed 200 IL instructions. The idea is that NDepend gets integrated into your NAnt or MSBuild process and that such a constraint emits a warning when it is not satisfied:
WARN IF Count > 0 IN SELECT METHODS
WHERE NbILinstructions > 200 ORDER BY NbILinstructions
In a real-world environment, there are often exceptions (like automatically generated methods which are often very big) and you need to allow a few particular methods to exceed this threshold without being bothered by our previous constraint. The CQL language offers numerous features allowing you to deal with such exceptions. For example, all generated methods might contain the word "Generated" in their names:
WARN IF Count > 0 IN SELECT METHODS
WHERE NbILinstructions > 200 AND !NameLike "Generated" ORDER BY NbILinstructions DESC
Or maybe, all generated methods are in dedicated assemblies, namespaces or types:
WARN IF Count > 0 IN SELECT METHODS
OUT OF NAMESPACES "MyApp.Generated1","MyApp.Generated2"
WHERE NbILinstructions > 200 ORDER BY NbILinstructions DESC
Or maybe, you prefer to mention each one explicitly:
WARN IF Count > 0 IN SELECT METHODS
WHERE NbILinstructions > 200 AND !(NameIs "Method1(int32)" OR FullNameIs "MyApp.MyType.Method2(String)" )
ORDER BY NbILinstructions DESC
You can also mix all these features in the same constraint:
WARN IF Count > 0 IN SELECT METHODS
OUT OF NAMESPACES "MyApp.Generated1","MyApp.Generated2"
WHERE NbILinstructions > 200 AND !(NameIs "Method1(int32)" OR FullNameIs "MyApp.MyType.Method2(String)" )
AND !NameLike "Generated" ORDER BY NbILinstructions DESC
Here are some examples of CQL queries based on code metrics:
SELECT TOP 5 METHODS WHERE IsPublic ORDER BY NbILinstructions DESC
| Name |
# IL instructions |
Full Name |
| GetClipboardContent() |
1911 |
System.Windows.Forms.DataGridView.GetClipboardContent() |
DrawBorder(Graphics,Rectangle,Color,int32,ButtonBorderStyle,
Color,int32,ButtonBorderStyle,Color,int32,ButtonBorderStyle,
Color,int32,ButtonBorderStyle) |
1354 |
System.Windows.Forms.ControlPaint.DrawBorder(
Graphics,Rectangle,Color,int32,ButtonBorderStyle,Color,
int32,ButtonBorderStyle,Color,int32,ButtonBorderStyle,
Color,int32,ButtonBorderStyle) |
| GetinheritedStyle(DataGridViewCellStyle,int32,Boolean) |
1116 |
System.Windows.Forms.DataGridViewCell.GetinheritedStyle(
DataGridViewCellStyle,int32,Boolean) |
BindToMethod(BindingFlags,MethodBase[],Object[]&,
ParameterModifier[],Cultureinfo,String[],Object&) |
1063 |
System.DefaultBinder.BindToMethod(BindingFlags,
MethodBase[],Object[]&,ParameterModifier[],Cultureinfo,
String[],Object&) |
| HitTest(int32,int32) |
1031 |
System.Windows.Forms.DataGridView.HitTest(int32,int32) |
SELECT TOP 5 METHODS WHERE IsPublic ORDER BY NbParameters DESC
| Name |
# Parameters |
Full Name |
GetAttributes(int32,String,String&,String,String&,
String,String&,String,String&,
String,String&,String,
String&,String,String&,String,
String&,String,String&,
String,String&) |
21 |
System.Xml.Xsl.Xslt.Xsltinput.GetAttributes(int32,String,String&,String,
String&,String,String&,String,String&,String,String&,String,String&,String,
String&,String,String&,String,String&,String,String&) |
GetAttributes(int32,String,String&,String,String&,
String,String&,String,String&,String,
String&,String,String&,String,String&,
String,String&,String,String&) |
19 |
System.Xml.Xsl.Xslt.Xsltinput.GetAttributes(int32,String,String&,String,
String&,String,String&,String,String&,String,String&,String,String&,String,
String&,String,String&,String,String&) |
.ctor(Byte,Byte,int32,Boolean,Boolean,Boolean,Byte,
Byte,String,Type,Type,
SqlDbType,DbType,Byte) |
14 |
System.Data.SqlClient.MetaType..ctor(Byte,Byte,int32,Boolean,Boolean,
Boolean,Byte,Byte,String,Type,Type,SqlDbType,DbType,Byte) |
DrawBorder(Graphics,Rectangle,Color,int32,
ButtonBorderStyle,Color,int32,
ButtonBorderStyle,Color,int32,ButtonBorderStyle,
Color,int32,ButtonBorderStyle)
|
14 |
System.Windows.Forms.ControlPaint.DrawBorder(Graphics,Rectangle,Color,
int32,ButtonBorderStyle,Color,int32,ButtonBorderStyle,Color,int32,
ButtonBorderStyle,Color,int32,ButtonBorderStyle) |
.ctor(String,SqlDbType,int32,ParameterDirection,
Byte,Byte,String,DataRowVersion,
Boolean,Object,String,String,String) |
13 |
System.Data.SqlClient.SqlParameter..ctor(String,SqlDbType,int32,
ParameterDirection,Byte,Byte,String,DataRowVersion,Boolean,
Object,String,String,String) |
SELECT TOP 5 TYPES WHERE IsPublic ORDER BY NbILinstructions DESC
| Name |
# IL instructions |
Full Name |
| DataGridView |
67328 |
System.Windows.Forms.DataGridView |
| BrowserCapabilitiesFactory |
45798 |
System.Web.Configuration.BrowserCapabilitiesFactory |
| Control |
18456 |
System.Windows.Forms.Control |
| DataGrid |
15799 |
System.Windows.Forms.DataGrid |
| DataTable |
13597 |
System.Data.DataTable |
SELECT TOP 5 TYPES WHERE IsPublic ORDER BY NbMethods DESC
| Name |
# Methods |
Full Name |
| BrowserCapabilitiesFactory |
1606 |
System.Web.Configuration.BrowserCapabilitiesFactory |
| DataGridView |
1053 |
System.Windows.Forms.DataGridView |
| Control |
869 |
System.Windows.Forms.Control |
| DataGrid |
421 |
System.Windows.Forms.DataGrid |
| Form |
349 |
System.Windows.Forms.Form |
SELECT TOP 5 TYPES WHERE !IsEnumeration AND IsPublic ORDER BY NbFields DESC
| Name |
# Fields |
Full Name |
| DataGridView |
322 |
System.Windows.Forms.DataGridView |
| OpCodes |
226 |
System.Reflection.Emit.OpCodes |
| HttpCapabilitiesBase |
224 |
System.Web.Configuration.HttpCapabilitiesBase |
| Control |
205 |
System.Windows.Forms.Control |
| Page |
143 |
System.Web.UI.Page |
SELECT TOP 5 TYPES WHERE IsPublic ORDER BY SizeOfInst DESC
| Name |
Size of instance |
Full Name |
| DataGridView |
556 |
System.Windows.Forms.DataGridView |
| ToolStripDropDownMenu |
478 |
System.Windows.Forms.ToolStripDropDownMenu |
| ContextMenuStrip |
478 |
System.Windows.Forms.ContextMenuStrip |
| PropertyGrid |
419 |
System.Windows.Forms.PropertyGrid |
| DataGrid |
408 |
System.Windows.Forms.DataGrid |
Here is the definition of the SizeOfInst (size of instances) metric: The size of instances of an instance field is defined as the size, in bytes, of instances of its type. The size of instance of a static field is equal to 0. The size of instances of a class or a structure is defined as the sum of size of instances of its fields plus the size of instances of its base class. Fields of reference types (class, interface, delegate...) always count for 4 bytes while the footprint of fields of value types (structure, int, byte, double...) might vary. Size of instances of an enumeration is equal to the size of instances of the underlying numeric primitive type. It is computed from the value__ instance field (all enumerations have such a field when compiled in IL). Size of instances of generic types might be erroneous because we can't statically know the footprint of parameter types (except when they have the class constraint).
SELECT TOP 5 TYPES OUT OF ASSEMBLIES "System.Windows.Forms","System.Web" WHERE IsPublic ORDER BY SizeOfInst DESC
| Name |
Size of instance |
Full Name |
| QueuePathDialog |
373 |
System.Messaging.Design.QueuePathDialog |
| XmlSerializationReader |
355 |
System.Xml.Serialization.XmlSerializationReader |
| HttpListenerResponse |
321 |
System.Net.HttpListenerResponse |
| DataTable |
265 |
System.Data.DataTable |
| HttpWebRequest |
236 |
System.Net.HttpWebRequest |
SELECT TOP 5 TYPES ORDER BY TypeCa DESC
| Name |
Afferent coupling at type level (TypeCa) |
Full Name |
| Void |
11940 |
System.Void |
| String |
11786 |
System.String |
| int32 |
11710 |
System.int32 |
| Boolean |
11687 |
System.Boolean |
| Object |
11670 |
System.Object |
Here is the definition of the TypeCa (afferent coupling) metric: The Afferent Coupling for a particular type is the number of types that depends directly on it.
SELECT TOP 5 TYPES ORDER BY TypeCe DESC
| Name |
Efferent coupling at type level (TypeCe) |
Full Name |
| DataGridView |
377 |
System.Windows.Forms.DataGridView |
| ListView |
313 |
System.Windows.Forms.ListView |
| Control |
299 |
System.Windows.Forms.Control |
| PropertyGrid |
274 |
System.Windows.Forms.PropertyGrid |
| AxHost |
270 |
System.Windows.Forms.AxHost |
Here is the definition of the TypeCe (efferent coupling) metric: The Efferent Coupling for a particular type is the number of types it directly depends on.
WARN IF Count > 0 IN SELECT TOP 10 TYPES
WHERE LCOMHS > 1.0 AND NbFields > 10 AND NbMethods > 10 ORDER BY LCOMHS DESC
| Name |
LCOM
Henderson-Sellers
(LCOMHS) |
# Fields |
# Methods |
Full Name |
| HealthMonitoringSection |
1.1 |
11 |
12 |
System.Web.Configuration.HealthMonitoringSection |
| ChineseLunisolarCalendar |
1.1 |
12 |
16 |
System.Globalization.ChineseLunisolarCalendar |
| KoreanLunisolarCalendar |
1.1 |
12 |
16 |
System.Globalization.KoreanLunisolarCalendar |
| RuleSettings |
1 |
13 |
22 |
System.Web.Configuration.RuleSettings |
| OutputCacheProfile |
1 |
11 |
24 |
System.Web.Configuration.OutputCacheProfile |
| RoleManagerSection |
1 |
14 |
28 |
System.Web.Configuration.RoleManagerSection |
| FormsAuthenticationConfiguration |
1 |
14 |
28 |
System.Web.Configuration.FormsAuthenticationConfiguration |
| ISAPIWorkerRequestinProc |
1 |
45 |
23 |
System.Web.Hosting.ISAPIWorkerRequestinProc |
| OutputCacheSection |
1 |
12 |
11 |
System.Web.Configuration.OutputCacheSection |
| PersianCalendar |
1 |
17 |
34 |
System.Globalization.PersianCalendar |
Here is the definition of the LCOMHS (Lack Of Cohesion Methods Henderson-Sellers) metric: The Efferent Coupling for a particular type is the number of types it directly depends on. The single responsibility principle states that a class should have more than one reason to change. Such a class is said to be cohesive. A high LCOM value generally pinpoints a poorly cohesive class. There are several LCOM metrics. The LCOM takes its values in the range [0-1]. The LCOM HS (HS stands for Henderson-Sellers) takes its values in the range [0-2]. A LCOM HS value highest than 1 should be considered alarming. Here are algorithms used by NDepend to compute LCOM metrics:
LCOM = (1-sum(MF)/M*F)
LCOM HS = (M- sum(MF)/F)(M-1)
Where:
M is the number of methods in class (both static and instance methods are counted, it includes also constructors, properties getters/setters, events add/remove methods).
F is the number of instance fields in the class.
MF is the number of methods of the class accessing a particular instance field.
Sum(MF) ids the sum of MF over all instance fields of the class.
SELECT TOP 5 NAMESPACES ORDER BY NbTypes DESC
| Name |
# Types |
Full Name |
| System.Windows.Forms |
1474 |
System.Windows.Forms |
| System.Web.UI.WebControls |
483 |
System.Web.UI.WebControls |
| System.Net |
445 |
System.Net |
| System.Xml.Schema |
298 |
System.Xml.Schema |
| System |
280 |
System |
SELECT TOP 5 TYPES WHERE IsPublic ORDER BY DepthOfInheritance DESC
| Name |
Depth of inheritance |
Full Name |
| ContextMenuStrip |
8 |
System.Windows.Forms.ContextMenuStrip |
| CatalogZone |
7 |
System.Web.UI.WebControls.WebParts.CatalogZone |
| ToolStripOverflow |
7 |
System.Windows.Forms.ToolStripOverflow |
| EditorZone |
7 |
System.Web.UI.WebControls.WebParts.EditorZone |
| QueuePathDialog |
7 |
System.Messaging.Design.QueuePathDialog |
SELECT TOP 5 TYPES OUT OF ASSEMBLIES "System.Windows.Forms","System.Web" WHERE IsPublic ORDER BY DepthOfInheritance DESC
| Name |
Depth of inheritance |
Full Name |
| QueuePathDialog |
7 |
System.Messaging.Design.QueuePathDialog |
| HttpGetClientProtocol |
6 |
System.Web.Services.Protocols.HttpGetClientProtocol |
| HttpPostClientProtocol |
6 |
System.Web.Services.Protocols.HttpPostClientProtocol |
| OleDbPermissionAttribute |
5 |
System.Data.OleDb.OleDbPermissionAttribute |
| IsolatedStorageFilePermissionAttribute |
5 |
System.Security.Permissions.IsolatedStorageFilePermissionAttribute |
Thanks to the NameLike "regex" CQL expression, you can write your own naming constraints. For example:
WARN IF Count > 0 IN SELECT TOP 5 FIELDS WHERE NameLike "^m_" AND IsStatic
| Name |
Size of instance |
Full Name |
| m_bitsPerByte |
0 |
System.Security.Cryptography.MACTripleDES.m_bitsPerByte |
| m_format |
0 |
System.Security.Cryptography.X509Certificates.X509Certificate.m_format |
| m_appTrustManager |
0 |
System.Security.Policy.ApplicationSecurityManager.m_appTrustManager |
| m_illegalCharacters |
0 |
System.Security.Permissions.FileIOPermission.m_illegalCharacters |
| m_strAllFiles |
0 |
System.Security.Permissions.FileIOAccess.m_strAllFiles |
WARN IF Count > 0 IN SELECT FIELDS WHERE NameLike "^s_" AND !IsStatic
| Name |
Size of instance |
Full Name |
| s_oneTimeinit |
1 |
System.Web.SessionState.SessionStateModule.s_oneTimeinit |
| s_internalSyncObject |
4 |
System.Security.Policy.HashMembershipCondition.s_internalSyncObject |
WARN IF Count > 0 IN SELECT TOP 10 TYPES WHERE IsInterface AND !NameLike "^I" AND !IsNested AND IsPublic
| Name |
# IL instructions |
Full Name |
| _AppDomain |
0 |
System._AppDomain |
| _Module |
0 |
System.Runtime.interopServices._Module |
| _Propertyinfo |
0 |
System.Runtime.interopServices._Propertyinfo |
| _Fieldinfo |
0 |
System.Runtime.interopServices._Fieldinfo |
| _Constructorinfo |
0 |
System.Runtime.interopServices._Constructorinfo |
| _Eventinfo |
0 |
System.Runtime.interopServices._Eventinfo |
| _Parameterinfo |
0 |
System.Runtime.interopServices._Parameterinfo |
| _Methodinfo |
0 |
System.Runtime.interopServices._Methodinfo |
| _AssemblyName |
0 |
System.Runtime.interopServices._AssemblyName |
| _Assembly |
0 |
System.Runtime.interopServices._Assembly |
Suppose that you need to know which methods can potentially trigger the call of a particular methods, such as a Split() overload of the System.String class. CQL answer this need thanks to the IsCalling keyword:
SELECT METHODS WHERE IsCalling "System.String.Split(Char[],int32,StringSplitOptions)" ORDER BY DepthOfIsCalling, NbILinstructions DESC
| Name |
DepthOfIsUsing
'"System.String.
Split(
Char[],int32,
StringSplitOptions)"'
|
# IL instructions |
Full Name |
| Split(Char[],int32,StringSplitOptions) |
0 |
80 |
System.String.Split(Char[],int32,StringSplitOptions) |
| Split(String[],int32,StringSplitOptions) |
1 |
97 |
System.String.Split(String[],int32,StringSplitOptions) |
| Split(Char[],int32) |
1 |
6 |
System.String.Split(Char[],int32) |
| Split(Char[]) |
1 |
6 |
System.String.Split(Char[]) |
| Split(Char[],StringSplitOptions) |
1 |
6 |
System.String.Split(Char[],StringSplitOptions) |
| ResolveWsdlMethodinfo(WsdlParser+WsdlBinding) |
2 |
770 |
System.Runtime.Remoting.MetadataServices.
WsdlParser.ResolveWsdlMethodinfo(
WsdlParser+WsdlBinding) |
| Create(String) |
2 |
575 |
System.Xml.Xsl.Runtime.XmlCollation.Create(String) |
| get_MiscSectionContent() |
2 |
571 |
System.Web.DynamicCompileErrorFormatter.
get_MiscSectionContent() |
| initOutputCache(OutputCacheParameters) |
2 |
513 |
System.Web.UI.Page.
initOutputCache(OutputCacheParameters) |
| ProcessRequest(HttpContext) |
2 |
495 |
System.Web.Handlers.AssemblyResourceLoader.
ProcessRequest(HttpContext) |
| OnEnter(Object,EventArgs) |
2 |
452 |
System.Web.Caching.OutputCacheModule.
OnEnter(Object,EventArgs) |
Read33_XmlSchemaSimpleTypeUnion
(Boolean,Boolean) |
2 |
373 |
System.Web.Services.Description.
ServiceDescriptionSerializationReader.
Read33_XmlSchemaSimpleTypeUnion(Boolean,Boolean) |
GetDefaultValueArguments(PrimitiveMapping,
Object,
CodeExpression&) |
2 |
372 |
System.Xml.Serialization.XmlCodeExporter.
GetDefaultValueArguments(PrimitiveMapping,
Object,CodeExpression&) |
| intersect(EndpointPermission) |
2 |
344 |
System.Net.EndpointPermission.
intersect(EndpointPermission) |
| RaisePostBackEvent(String) |
2 |
316 |
System.Web.UI.WebControls.WebParts.
WebPartZoneBase.RaisePostBackEvent(String) |
| ...(47869 methods selected) |
|
|
|
The CQL query above allows to see that 37.7% (47869 on 127034 with a maximum DepthOfIsCalling equal to 30) of the methods of the .NET framework 2.0 can potentially trigger the call of this overload of the Split() method of the System.String class.
You might be more interested by knowing just which methods call this method directly:
SELECT METHODS WHERE DepthOfIsCalling "System.String.Split(Char[],int32,StringSplitOptions)" == 1 ORDER BY DepthOfIsCalling
| Name |
DepthOfIsUsing
'"System.String.
Split(Char[],int32,
StringSplitOptions)"' |
Full Name |
| Split(Char[],StringSplitOptions) |
1 |
System.String.Split(Char[],StringSplitOptions) |
| Split(Char[],int32) |
1 |
System.String.Split(Char[],int32) |
| Split(String[],int32,StringSplitOptions) |
1 |
System.String.Split(String[],int32,StringSplitOptions) |
| Split(Char[]) |
1 |
System.String.Split(Char[]) |
On the opposite, you can use the keywords IsCalledBy and DepthOfIsCalledBy:
SELECT METHODS WHERE IsCalledBy "System.String.Split(Char[],int32,StringSplitOptions)"
ORDER BY DepthOfIsCalledBy
| Name |
DepthOfIsUsedBy
'"System.String.
Split(Char[],int32,
StringSplitOptions)"' |
Full Name |
| Split(Char[],int32,StringSplitOptions) |
0 |
System.String.Split(Char[],int32,StringSplitOptions) |
internalSplitKeepEmptyEntries(
int32[],int32[],int32,int32) |
1 |
System.String.internalSplitKeepEmptyEntries(int32[],int32[],int32,int32) |
| .ctor(String,String) |
1 |
System.ArgumentOutOfRangeException..ctor(String,String) |
| get_Length() |
1 |
System.String.get_Length() |
| GetResourceString(String) |
1 |
System.Environment.GetResourceString(String) |
internalSplitOmitEmptyEntries(int32[],
int32[],int32,int32) |
1 |
System.String.internalSplitOmitEmptyEntries(int32[],
int32[],int32,int32) |
| MakeSeparatorList(Char[],int32[]&) |
1 |
System.String.MakeSeparatorList(Char[],int32[]&) |
| GetResourceString(String,Object[]) |
1 |
System.Environment.GetResourceString(String,Object[]) |
| .ctor(String) |
1 |
System.ArgumentException..ctor(String) |
| GetResourceFromDefault(String) |
2 |
System.Environment.GetResourceFromDefault(String) |
| Substring(int32) |
2 |
System.String.Substring(int32) |
| .ctor(String) |
2 |
System.SystemException..ctor(String) |
| .ctor(String,String) |
2 |
System.ArgumentException..ctor(String,String) |
| SetErrorCode(int32) |
2 |
System.Exception.SetErrorCode(int32) |
| Format(IFormatProvider,String,Object[]) |
2 |
System.String.Format(IFormatProvider,String,Object[]) |
| IsWhiteSpace(Char) |
2 |
System.Char.IsWhiteSpace(Char) |
| get_CurrentCulture() |
2 |
System.Globalization.Cultureinfo.get_CurrentCulture() |
| Substring(int32,int32) |
2 |
System.String.Substring(int32,int32) |
| .ctor(String) |
3 |
System.ArgumentNullException..ctor(String) |
internalSubStringWithChecks(
int32,int32,Boolean) |
3 |
System.String.internalSubStringWithChecks(int32,int32,Boolean) |
| ...(744 methods selected) |
|
|
In the same spirit the CQL language provides the keywords IsUsing, DepthOfIsUsing IsUsedBy DepthOfIsUsedBy usable in the assemblies, namespaces or types context. The keywords CreateA and DepthOfCreateA can also be used to know which method can be responsible for calling the constructor of a type:
SELECT METHODS WHERE DepthOfCreateA "System.Diagnostics.Process" < 3 ORDER BY DepthOfCreateA
| Name |
DepthOfCreateA "System.Diagnostics.
Process" |
Full Name |
| .ctor(String,Boolean,int32,Processinfo) |
0 |
System.Diagnostics.Process..ctor(String,Boolean,int32,Processinfo) |
| .ctor() |
0 |
System.Diagnostics.Process..ctor() |
| GetProcessById(int32,String) |
1 |
System.Diagnostics.Process.GetProcessById(int32,String) |
| GetProcesses(String) |
1 |
System.Diagnostics.Process.GetProcesses(String) |
| GetCurrentProcess() |
1 |
System.Diagnostics.Process.GetCurrentProcess() |
| Start(ProcessStartinfo) |
1 |
System.Diagnostics.Process.Start(ProcessStartinfo) |
| GetProcessById(int32) |
2 |
System.Diagnostics.Process.GetProcessById(int32) |
| Start(String,String) |
2 |
System.Diagnostics.Process.Start(String,String) |
| Restart() |
2 |
System.Windows.Forms.Application.Restart() |
| initProcessinfo() |
2 |
System.Diagnostics.TraceEventCache.initProcessinfo() |
| get_ProcessName() |
2 |
System.Transactions.Diagnostics.DiagnosticTrace.get_ProcessName() |
| get_ProcessId() |
2 |
System.Transactions.Diagnostics.DiagnosticTrace.get_ProcessId() |
| LoadPerfCounterDll() |
2 |
System.Diagnostics.CounterSampleCalculator.LoadPerfCounterDll() |
| Start(String) |
2 |
System.Diagnostics.Process.Start(String) |
| GetProcesses() |
2 |
System.Diagnostics.Process.GetProcesses() |
| RegisterFiles(String,Boolean) |
2 |
System.Diagnostics.PerformanceCounterLib.RegisterFiles(String,Boolean) |
| .cctor() |
2 |
System.Web.Management.WebProcessStatistics..cctor() |
| GetDefaultAppName() |
2 |
System.Web.Util.SecUtility.GetDefaultAppName() |
| GetDataDirectory() |
2 |
System.Web.DataAccess.SqlConnectionHelper.GetDataDirectory() |
| initApp() |
2 |
System.Web.Security.AuthorizationStoreRoleProvider.initApp() |
| Update() |
2 |
System.Web.Management.WebProcessStatistics.Update() |
| .ctor() |
2 |
System.Web.Management.WebProcessStatistics..ctor() |
| RuntimeDatainitialize() |
2 |
System.Web.Configuration.MachineKeySection.RuntimeDatainitialize() |
| Start(String,String,String,SecureString,String) |
2 |
System.Diagnostics.Process.Start(String,String,String,SecureString,String) |
| Start(String,String,SecureString,String) |
2 |
System.Diagnostics.Process.Start(String,String,SecureString,String) |
| GetinstanceName() |
2 |
System.Net.NetworkingPerfCounters.GetinstanceName() |
| get_Identifier() |
2 |
System.Net.Networkinformation.IcmpPacket.get_Identifier() |
| GetProcessesByName(String,String) |
2 |
System.Diagnostics.Process.GetProcessesByName(String,String) |
These keywords can be used in custom CQL constraints to ensure that some kind of encapsulation will be respected. For example you might wish to restrict the possibility of using the type "System.Xml.XmlChildNodes" only to certain namespace.
WARN IF Count > 0 IN SELECT TYPES OUT OF NAMESPACES "System.Xml" WHERE DepthOfIsUsing "System.Xml.XmlChildNodes" == 1
Or you might wish to restrict the possibility of creating instance of "System.Xml.XmlLoader" only to certain namespaces.
WARN IF Count > 0 IN SELECT METHODS OUT OF NAMESPACES "System.Xml"
WHERE DepthOfCreateA "System.Xml.XmlLoader" == 1 ORDER BY DepthOfCreateA
Or you want to assert that the assembly System.Web.Services will never be referenced by another assembly than System.Web:
WARN IF Count > 0 IN SELECT ASSEMBLIES WHERE !NameIs "System.Web" AND DepthOfIsUsing "System.Web.Services" == 1
Let's precise that the CQL language provides also the keywords Implements DeriveFrom and DepthOfDeriveFrom
SELECT TYPES WHERE DepthOfDeriveFrom "System.Windows.Forms.Control" == 1
| Name |
DepthOfDeriveFrom 'Control' |
Full Name |
| DataGridView |
1 |
System.Windows.Forms.DataGridView |
| DataGrid |
1 |
System.Windows.Forms.DataGrid |
| ListView |
1 |
System.Windows.Forms.ListView |
| AxHost |
1 |
System.Windows.Forms.AxHost |
| TreeView |
1 |
System.Windows.Forms.TreeView |
| MonthCalendar |
1 |
System.Windows.Forms.MonthCalendar |
| TabControl |
1 |
System.Windows.Forms.TabControl |
| TextBoxBase |
1 |
System.Windows.Forms.TextBoxBase |
| ToolBar |
1 |
System.Windows.Forms.ToolBar |
| ScrollableControl |
1 |
System.Windows.Forms.ScrollableControl |
| Label |
1 |
System.Windows.Forms.Label |
| WebBrowserBase |
1 |
System.Windows.Forms.WebBrowserBase |
| DateTimePicker |
1 |
System.Windows.Forms.DateTimePicker |
| PrintPreviewControl |
1 |
System.Windows.Forms.PrintPreviewControl |
| PictureBox |
1 |
System.Windows.Forms.PictureBox |
| StatusBar |
1 |
System.Windows.Forms.StatusBar |
| ButtonBase |
1 |
System.Windows.Forms.ButtonBase |
| Splitter |
1 |
System.Windows.Forms.Splitter |
| TrackBar |
1 |
System.Windows.Forms.TrackBar |
| ListControl |
1 |
System.Windows.Forms.ListControl |
| GroupBox |
1 |
System.Windows.Forms.GroupBox |
| ScrollBar |
1 |
System.Windows.Forms.ScrollBar |
| ProgressBar |
1 |
System.Windows.Forms.ProgressBar |
| MdiClient |
1 |
System.Windows.Forms.MdiClient |
| UpDownBase+UpDownButtons |
1 |
System.Windows.Forms.UpDownBase+UpDownButtons |
| StatusStrip+RightToLeftLayoutGrip |
1 |
System.Windows.Forms.StatusStrip+RightToLeftLayoutGrip |
| PropertyGrid+SnappableControl |
1 |
System.Windows.Forms.PropertyGrid+SnappableControl |
| Application+MarshalingControl |
1 |
System.Windows.Forms.Application+MarshalingControl |
| SendKeys+SKWindow |
1 |
System.Windows.Forms.SendKeys+SKWindow |
| PropertyGridView |
1 |
System.Windows.Forms.PropertyGridinternal.PropertyGridView |
| GridToolTip |
1 |
System.Windows.Forms.PropertyGridinternal.GridToolTip |
| ContentAlignmentEditor+ContentUI |
1 |
System.Drawing.Design.ContentAlignmentEditor+ContentUI |
| ColorEditor+ColorUI |
1 |
System.Drawing.Design.ColorEditor+ColorUI |
| ColorEditor+ColorPalette |
1 |
System.Drawing.Design.ColorEditor+ColorPalette |
SELECT TYPES WHERE Implement "System.ComponentModel.IComponent"
| Name |
# IL instructions |
Full Name |
| DataGridView |
67328 |
System.Windows.Forms.DataGridView |
| Control |
18456 |
System.Windows.Forms.Control |
| DataGrid |
15799 |
System.Windows.Forms.DataGrid |
| DataTable |
13597 |
System.Data.DataTable |
| ListView |
10875 |
System.Windows.Forms.ListView |
| Form |
10234 |
System.Windows.Forms.Form |
| PropertyGridView |
9679 |
System.Windows.Forms.PropertyGridinternal.PropertyGridView |
| PropertyGrid |
8122 |
System.Windows.Forms.PropertyGrid |
| WebPartManager |
7880 |
System.Web.UI.WebControls.WebParts.WebPartManager |
| GridView |
7059 |
System.Web.UI.WebControls.GridView |
| ToolStrip |
6762 |
System.Windows.Forms.ToolStrip |
| Page |
6712 |
System.Web.UI.Page |
| TreeView |
6396 |
System.Web.UI.WebControls.TreeView |
| DataSet |
6112 |
System.Data.DataSet |
| AxHost |
5888 |
System.Windows.Forms.AxHost |
| DetailsView |
5835 |
System.Web.UI.WebControls.DetailsView |
| RichTextBox |
5684 |
System.Windows.Forms.RichTextBox |
| SqlCommand |
5482 |
System.Data.SqlClient.SqlCommand |
| ComboBox |
5421 |
System.Windows.Forms.ComboBox |
| TreeView |
5204 |
System.Windows.Forms.TreeView |
| Menu |
5034 |
System.Web.UI.WebControls.Menu |
| MessageQueue |
4899 |
System.Messaging.MessageQueue |
| EventLog |
4709 |
System.Diagnostics.EventLog |
| WebClient |
4687 |
System.Net.WebClient |
| ConnectionsZone |
4543 |
System.Web.UI.WebControls.WebParts.ConnectionsZone |
| CreateUserWizard |
4266 |
System.Web.UI.WebControls.CreateUserWizard |
| FormView |
4250 |
System.Web.UI.WebControls.FormView |
| ToolStripItem |
4192 |
System.Windows.Forms.ToolStripItem |
| ToolTip |
4072 |
System.Windows.Forms.ToolTip |
| SplitContainer |
4040 |
System.Windows.Forms.SplitContainer |
| ... (443 types selected) |
|
|
This article doesn't illustrate all capabilities of the CQL language.
You can learn this language by reading CQL 1.0 specification and you can use it on your own .NET application by downloading NDepend 2.0.
Patrick Smacchia is a .NET MVP involved in software development for over 15 years. He is the author of Practical .NET2 and C#2, a .NET book conceived from real world experience with 647 compilable code listings. After graduating in mathematics and computer science, he has worked on software in a variety of fields including stock exchange at Société Générale, airline ticket reservation system at Amadeus as well as a satellite base station at Alcatel. He's currently a software consultant and trainer on .NET technologies as well as the author of the freeware NDepend which provides numerous metrics and caveats on any compiled .NET application. |