Proving a Point with LINQ (or, the Longest Type Names in the .NET Framework)

Proving a Point with LINQ (or, the Longest Type Names in the .NET Framework)

  • Comments 1

I will often take a few moments during a presentation to get a chuckle by bringing up the SharedConnectionWorkflowCommitWorkBatchService.  Due to the sheer length of the type name, it's sure to bring a smile or two in one of my otherwise snore-inducing presentation.

The other day, while reviewing a deck for a colleague I brought up that he should mention this type, and that it usually gets a laugh from a developer audience.  He then asked, "Is that really the longest type name in the framework?"  My response, "Well, I'm not really sure, I bet you could do some LINQ magic in order to figure it out." 

Well, sitting on the bus this morning with some traffic time to spare (and needing to work on my LINQ skills a bit), put together some code.  My goal was to go through all of the types, calculate their length and figure out which one was the longest named type.  You can replicate this, create a new console application, right click to add references, and select all the references you want to add into this comparison.  I added all of the system.* assemblies, PresentationFramework, PresentationCore and WindowBase.  You could do even more by selecting everything in the reference dialog.

The thing that appeals to me about LINQ is really that i can just write a query, I don't have to worry about looping through a number of times.  I also like the fact I can develop by refining, that is, I can get a collection back, tweak the query to shape it, take that new collection and query against that.

Let's first look at what I started with:

var orderedTypeListing =
       (from assembly in AppDomain.CurrentDomain.GetAssemblies()
        select assembly.GetExportedTypes());

This ends up returning an object of type IEnumerable<List<Type>>, which doesn't quite get me to what I want.

I use the Aggregate extension method to operate on this and create an entire list of all the types contained (think of this as flattening the tree by one level, or only returning the leaf nodes in the tree).  With the Aggregate method, I need to provide the operation to do the accumulation.

var orderedTypeListing =
   (from assembly in AppDomain.CurrentDomain.GetAssemblies()
     select assembly.GetExportedTypes()).Aggregate(
           (x, y) =>
           { return x.Union(y).ToArray(); }
        )

The only weirdness here is that I have to use ToArray(); since Aggregate returns T[], rather than IEnumerable<T>.

Now I add a little bit of code to do some ordering.  I like the ordering syntax since I just provide a way to get the value I want to sort by.  Remember to use OrderByDescending in order to get the right ordering.

Our query near looks like this:

var orderedTypeListing =
   (from assembly in AppDomain.CurrentDomain.GetAssemblies()
     select assembly.GetExportedTypes()).Aggregate(
           (x, y) =>
           { return x.Union(y).ToArray(); }
        ).OrderByDescending(
            (x) =>
            { return x.Name.Length; }
        );

So this returns a list, ordered by the length of the name.

I could just grab the first one off the list, and I'd be done, but I'd like to see the 100 longest names, just in case I'm wrong about our friend SharedConnectionWorkflowCommitWorkBatchService.   To do this, I'll say I want to take 100 off the top of the list and print those out. 

int count = 1;
orderedTypeListing.Take(100).ToList().ForEach
(
    x => 
    Console.WriteLine("{0}: {1}, {3} ({2})", 
    count++, 
    x.Name.Length, 
    x.Assembly.FullName.Split(",".ToCharArray())[1], 
    x.Name)
    );

This will pretty print the top 100 longest names (these are at the bottom of the post).

Next, i thought, I'd really like to see a histogram of the sizes.  To do that, I need to group by data.  The Group() extension method, just like the order method, allows me to pass in the value by which I want to group (and that can be computed, say a hash).  It also returns an IGrouping that lets me see the key (in my case, the size of the key) and the IEnumerable itself.

var groupedTypeListing = orderedTypeListing.GroupBy(
    t => 
    { return t.Name.Length; }
    );
groupedTypeListing.ToList().ForEach(
    x => 
        Console.WriteLine("{0} : {1}", x.Key, x.Count())
        );

Finally, I thought I'd see just how many types were included in each version of the framework, and prove that I can group by anything, including manipulating the string on the assembly's full name.

var groupedVersionListing = orderedTypeListing.GroupBy(
    t => 
    { return t.Assembly.FullName.Split(",".ToCharArray())[1]; }
    );
groupedVersionListing.ToList().ForEach(
    x => 
        Console.WriteLine("{0} : {1}", x.Key, x.Count()
        )
);

This has now let me retrieve a lot of interesting data (interesting at least to me :-) ) that I was able to write with a pretty simple query syntax and do some somewhat sophisticated things (grouping, etc).

It turns out that our friend SharedConnectionWorkflowCommitWorkBatchService is only number 16 on my list.  The real honor goes to:

 

AttachedPropertyBrowsableWhenAttributePresentAttribute, with 53 characters.

 

 

Histogram of Type Name Sizes

image

 

Top 100 Longest Type Names

Rank Length Name Version
1 54  AttachedPropertyBrowsableWhenAttributePresentAttribute   v3.0
2 53  ListViewVirtualItemsSelectionRangeChangedEventHandler   v2.0
3 52  ServiceModelEnhancedConfigurationElementCollection`1   v3.0
4 50  DataGridViewCellContextMenuStripNeededEventHandler   v2.0
5 50  ListViewVirtualItemsSelectionRangeChangedEventArgs   v2.0
6 49  DataGridViewRowContextMenuStripNeededEventHandler   v2.0
7 49  WorkflowServiceAttributesDynamicPropertyValidator   v3.5
8 48  DataGridViewColumnDividerDoubleClickEventHandler   v2.0
9 47  DataGridViewCellContextMenuStripNeededEventArgs   v2.0
10 47  DataGridViewCellStyleContentChangedEventHandler   v2.0
11 47  ReadOnlyActiveDirectorySchemaPropertyCollection   v2.0
12 47  ExtendedWorkflowRuntimeServiceElementCollection   v3.5
13 46  IDataGridColumnStyleEditingNotificationService   v2.0
14 46  DataGridViewRowContextMenuStripNeededEventArgs   v2.0
15 46  UpdateProgressAssociatedUpdatePanelIDConverter   v3.5
16
46
 SharedConnectionWorkflowCommitWorkBatchService 
 v3.0
17 46  DispatcherUnhandledExceptionFilterEventHandler   v3.0
18 45  DataGridViewColumnDividerDoubleClickEventArgs   v2.0
19 45  DataGridViewCellToolTipTextNeededEventHandler   v2.0
20 45  DataGridViewEditingControlShowingEventHandler   v2.0
21 45  DataGridViewRowDividerDoubleClickEventHandler   v2.0
22 45  NamedServiceModelExtensionCollectionElement`1   v3.0
23 45  StandardBindingOptionalReliableSessionElement   v3.0
24 45  X509CertificateTrustedIssuerElementCollection   v3.0
25 45  X509ScopedServiceCertificateElementCollection   v3.0
26 45  InitiatorServiceModelSecurityTokenRequirement   v3.0
27 45  RecipientServiceModelSecurityTokenRequirement   v3.0
28 45  DataContractSerializerMessageContractImporter   v3.0
29 45  ClientWindowsAuthenticationMembershipProvider   v3.5
30 45  IClientFormsAuthenticationCredentialsProvider   v3.5
31 45  AttachedPropertyBrowsableForChildrenAttribute   v3.0
32 44  DataGridViewCellStyleContentChangedEventArgs   v2.0
33 44  DataGridViewColumnDesignTimeVisibleAttribute   v2.0
34 44  CodeParameterDeclarationExpressionCollection   v2.0
35 44  ReadOnlyActiveDirectorySchemaClassCollection   v2.0
36 44  ServiceModelConfigurationElementCollection`1   v3.0
37 44  UseManagedPresentationBindingElementImporter   v3.0
38 44  WS2007FederationHttpBindingCollectionElement   v3.0
39 43  KeyContainerPermissionAccessEntryCollection   v2.0
40 43  KeyContainerPermissionAccessEntryEnumerator   v2.0
41 43  DataGridViewAutoSizeColumnsModeEventHandler   v2.0
42 43  DataGridViewCellErrorTextNeededEventHandler   v2.0
43 43  DataGridViewRowHeightInfoNeededEventHandler   v2.0
44 43  DataGridViewRowHeightInfoPushedEventHandler   v2.0
45 43  PerformanceCounterPermissionEntryCollection   v2.0
46 43  TypeUniqueIdentifierSchemaImporterExtension   v2.0
47 43  IRemoteArgumentDictionaryEnumeratorContract   v2.0
48 43  ForeignKeyReferenceAlreadyHasValueException   v3.5
49 43  SecurityPackageContextConnectionInformation   v2.0
50 43  PrintSystemObjectPropertiesChangedEventArgs   v3.0
51 43  IssuedTokenClientBehaviorsElementCollection   v3.0
52 43  IssuedTokenParametersEndpointAddressElement   v3.0
53 43  X509ServiceCertificateAuthenticationElement   v3.0
54 43  TransportConfigurationTypeElementCollection   v3.0
55 43  ClientFormsAuthenticationMembershipProvider   v3.5
56 43  ServiceDescriptionFormatExtensionCollection   v2.0
57 43  DispatcherUnhandledExceptionFilterEventArgs   v3.0
58 42  DataGridViewCellToolTipTextNeededEventArgs   v2.0
59 42  DataGridViewEditingControlShowingEventArgs   v2.0
60 42  DataGridViewAutoSizeColumnModeEventHandler   v2.0
61 42  DataGridViewColumnStateChangedEventHandler   v2.0
62 42  DataGridViewRowErrorTextNeededEventHandler   v2.0
63 42  DataGridViewRowDividerDoubleClickEventArgs   v2.0
64 42  ToolStripItemDesignerAvailabilityAttribute   v2.0
65 42  EdmRelationshipNavigationPropertyAttribute   v3.5
66 42  BehaviorServiceAdornerCollectionEnumerator   v2.0
67 42  DirectoryServicesPermissionEntryCollection   v2.0
68 42  ForestTrustRelationshipCollisionCollection   v2.0
69 42  X509ClientCertificateAuthenticationElement   v3.0
70 42  ServiceControllerPermissionEntryCollection   v2.0
71 42  DatabaseNotEnabledForNotificationException   v2.0
72 42  DesignTimeResourceProviderFactoryAttribute   v2.0
73 41  CryptographicUnexpectedOperationException   v2.0
74 41  DataGridPreferredColumnWidthTypeConverter   v2.0
75 41  IDesignTimeResourceProviderFactoryService   v2.0
76 41  SiteMapDesignerHierarchicalDataSourceView   v2.0
77 41  WindowsUserNameSecurityTokenAuthenticator   v3.0
78 41  PrintSystemObjectPropertyChangedEventArgs   v3.0
79 41  ConnectionOrientedTransportBindingElement   v3.0
80 41  SecurityContextSecurityTokenAuthenticator   v3.0
81 41  SecureConversationSecurityTokenParameters   v3.0
82 41  X509CertificateInitiatorServiceCredential   v3.0
83 41  X509CertificateRecipientServiceCredential   v3.0
84 41  RecordDescriptionToTypeReferenceConverter   v3.0
85 41  BlobMessageEncodingBindingElementImporter   v3.0
86 41  DistributedTransactionPermissionAttribute   v2.0
87 41  CompositeActivityDesignerLayoutSerializer   v3.0
88 41  SqlPersistenceWorkflowInstanceDescription   v3.0
89 41  AttachedPropertyBrowsableForTypeAttribute   v3.0
90 40  DataGridViewAutoSizeColumnsModeEventArgs   v2.0
91 40  DataGridViewCellErrorTextNeededEventArgs   v2.0
92 40  DataGridViewCellStateChangedEventHandler   v2.0
93 40  DataGridViewRowHeightInfoNeededEventArgs   v2.0
94 40  DataGridViewRowHeightInfoPushedEventArgs   v2.0
95 40  ListViewItemSelectionChangedEventHandler   v2.0
96 40  DesignerSerializationVisibilityAttribute   v2.0
97 40  TypeSmallDateTimeSchemaImporterExtension   v2.0
98 40  SchemaImporterExtensionElementCollection   v2.0
99 40  ProtectedConfigurationProviderCollection   v2.0
100 40  DirectoryAttributeModificationCollection   v2.0