Click here to Skip to main content
15,860,861 members
Articles / Programming Languages / C#

LINQ to Visual Studio Solution

Rate me:
Please Sign up or sign in to vote.
4.20/5 (7 votes)
1 Dec 2009CPOL3 min read 28.4K   222   16   5
Search properties of projects within a solution using LINQ.

Image 1

A screenshot from LINQPad showing an example use of this code.

Introduction

In attempting to write software for Windows Mobile using Visual Studio C# Express or SharpDevelop, I found that there is some common code that is generated by the designers which does not work on Windows Mobile. Instead of fixing it by hand every time I changed something on the form, I wanted to write a general refactoring tool that I could run from the command line (or the "Tools" menu) and fix the problem code.

I got something very ugly working, using (or misusing) the NRefactory library from SharpDevelop. However, I found that sometimes I needed to use Reflection, and so I needed to know which libraries were referenced in the project. At this point, I had never used LINQ, but I started to see how LINQ to XML could save a lot of code.

Then, as I was working on it, the code to get project properties evolved into the general purpose LINQ to Visual Studio solution that I present here. There is nothing in this code that deals with refactoring. It does read only property queries against Visual Studio projects. Hopefully, at some point, my refactoring code will be at a decent stage and I can post an article on that.

Background

As I already stated, I had never used LINQ until a few days ago. Not all of this code is very pretty, and there may be a simpler/better way to implement some of the features in this code. If there is, I would appreciate advice. Having said that, when I ran a series of queries against the many solution files / projects on my computer, it performed very well.

Using the Code

To use the demo application, simply start it from the command line, passing a directory you want to scan recursively for solution files and projects. It outputs a summary of each solution/project to output.txt in the application directory. In the code for the demo application, there are several other queries you can try that are commented out. I recommend that you look at those to see some of the possibilities of this library.

Add a reference to LinqToVisualStudioSolution.dll that is found in the demo download. Add a using directive for the LinqToVisualStudioSolution namespace. Now, you are ready to use the code.

C#
using System;
using LinqToVisualStudioSolution;

class Program
{
   static void Main(string[] args)
   {
       // Change the path to a real solution file.
       Solution solution = new Solution(@"D:\temp\Test.sln");

       var projects = (from project in solution
                       where project.OutputType == OutputType.Library
                       select project);

       foreach (var project in projects)
       {
         
            Console.Write("Project: ");
            Console.WriteLine(project.ProjectName);

            // OutputPathToAssemblyFull is a calculated property from 
            // OutputPathFull (another calculation), AssemblyName, and OutputType.

            Console.WriteLine(project.OutputPathToAssemblyFull);
            Console.WriteLine();
            if (project.Errors.Count > 0)
            {
                Console.ForegroundColor = ConsoleColor.Red;
                foreach (string err in project.Errors)
                {
                    Console.WriteLine(err);
                }
                Console.ResetColor();
            }
       }
   }
}

Points of Interest

The hardest part of my code was getting the Element(s) and Attribute(s) features working so that the user can access any property in the project, not only the common ones. I had to create a class, PElement, that inherits from XElement. The reason for this is to keep the user from having to include the namespace in his queries. So instead of writing the following:

C#
XNamespace ns = "http://schemas.microsoft.com/developer/msbuild/2003";

var projects = (from project in solution
                where project.Element(ns + "PropertyGroup") != null &&
                project.Element(ns + "PropertyGroup")
                .Element(ns + "AssemblyName") != null &&
                project.Element(ns + "PropertyGroup")
                .Element(ns + "AssemblyName").Value == "Test"
                select project); 

you can forget about the XNamespace altogether.

In order to accomplish this, I had to write a couple of extension methods for the IEnumerable<PElement> class. These can be found at the beginning of the PElement.cs file.

I also wrote an extension method for the IEnumerable<Reference> class so I could have a custom Contains method. Now, you can search for projects that contain certain references.

C#
var projects = (from project in solution
                 where project.References.Contains("mscorlib")
                 select project);

Conclusion

I had fun writing this code and learned a lot from it, including how powerful LINQ is. Hopefully, this will be of some use to others.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Other
South Africa South Africa
Joel Williams is a professional software developer turned preacher. Since he moved to South Africa, he has been out of the software industry for several years, but he tries to keep his skills sharp through hobby programming.

While developing professionally, Joel mostly used VB.NET and ASP.NET, but he now prefers C# and Windows Forms or Windows Mobile development.

Comments and Discussions

 
GeneralAnother alternative Pin
Colin Eberhardt2-Dec-09 4:27
Colin Eberhardt2-Dec-09 4:27 
GeneralRe: Another alternative Pin
joelwms2-Dec-09 7:17
joelwms2-Dec-09 7:17 
That is definitely cleaner than my example with the namespace use. I suppose for the target audience of this code, that wouldn't be too hard to remember, but if someone forgets to add the namespace, it is really frustrating trying to figure out why no data is being returned.

So yes, this technique would make my code easier and cleaner, but it would make it a little more difficult for the end-users (including me). If someone else is using this code for something, they may want to clear out the subclasses to make it easier to support, but I am enjoying not needing to remember the namespace.

Thanks for the suggestion.

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.