Click or drag to resize

Loading Sources

Examples of loading C# source code into a tree of code objects.

Load an entire Solution, parsing and resolving it
C#
// Load a solution, specifying the configuration and platform - these are optional, but the configuration can affect
// conditionally compiled code, and the platform will determine the output directory used to load generated files.
// Also, turn on logging of metrics and messages.
Solution solution = Solution.Load("Nova.Examples.sln", "Debug", "x86", LoadOptions.Complete | LoadOptions.LogAll);
if (solution != null)
    Log.WriteLine("Solution '" + solution.Name + "' successfully loaded, parsed, resolved.");

If successful, a Solution object is returned, otherwise null. By default, a Complete load is done, but this can be overridden.

A Complete load of a Solution goes through the following steps:

  • Parse the Solution file, creating a Solution object and a list of SolutionProjectEntry objects.

  • Parse each Project file, creating a Project object and loading the lists of References and code files (CodeUnit).

  • Resolve all References for each project, and determine the project dependencies.

  • Load all referenced assemblies for each project (in dependency order).

  • Load all types from all referenced assemblies for each project (in dependency order).

  • Parse all code files for each project (in dependency order), first loading all types from any referenced projects.

  • Resolve all symbolic references in all code files for each project (in dependency order).

The LoadOptions.LoadOnly option stops this process after parsing the Solution and Project files and resolving References, which is useful if only the solution and/or project files are being viewed, analyzed, or edited. The DoNotResolve option skips resolving symbolic references, which is useful if that step is not required, such as when only formatting code or calculating metrics which don't rely on resolved references.

Source code is loaded into a semantic tree of pure code objects, without separate objects for syntax (such as braces), but formatting information and comments are retained on these objects. By default, code will be re-formatted according to the default formatting rules when displayed or saved, but this can be controlled with options. Also, newlines are generally retained as-is in loaded code, so that changes will be minimal unless re-formatting is explicitly performed.

Load a Solution WITHOUT parsing or resolving it

This is useful to only analyze and/or modify the Solution and/or Projects.

C#
Solution solution = Solution.Load("Nova.Examples.sln", LoadOptions.LoadOnly);
if (solution != null)
    Log.WriteLine("Solution '" + solution.Name + "' successfully loaded without parsing or resolving source files.");
Load a Solution and parse it, but don't resolve it

This is useful if only formatting or other processes that don't require resolving symbolic references.

C#
Solution solution = Solution.Load("Nova.Examples.sln", LoadOptions.DoNotResolve);
if (solution != null)
    Log.WriteLine("Solution '" + solution.Name + "' successfully loaded and parsed, but not resolved.");
Load a single Project, parsing and resolving it

This is useful for working on a single project of a solution. Any missing project references will be treated as assembly references so that symbols can be resolved.

C#
// Load a project, specifying the configuration and platform - these are optional, but the configuration can affect
// conditionally compiled code, and the platform will determine the output directory used to load generated files.
Project project = Project.Load("Nova.Examples.csproj", "Debug", "x86");
if (project != null)
    Log.WriteLine("Project '" + project.Name + "' successfully loaded, parsed, resolved.");

If successful, a Project object is returned, otherwise null. By default, a Complete load is done, but this can be overridden.

Loading a Project directly goes through the following steps:

  • Parse the Project file, creating a Project object and loading the lists of References and code files (CodeUnits).

  • Resolve all References for the project.

  • Load all referenced assemblies.

  • Load all types from all referenced assemblies.

  • Parse all code files.

  • Resolve all symbolic references in all code files.

The LoadOptions.LoadOnly option stops this process after parsing the Project file and resolving References, which is useful if only the project file itself is being viewed, analyzed, or edited. The DoNotResolve option skips resolving symbolic references, which is useful if that step is not required, such as when only formatting code or calculating metrics which don't rely on resolved references.

Load a single CodeUnit (source file), parsing and resolving it
C#
// When loading a CodeUnit directly, all external symbolic references will fail to resolve, because we have no Project
// and therefore no assembly references.  Internal references (to locals, parameters, members of the same type, etc)
// will still be resolved.  See the LoadCodeUnits() example for how external references can be resolved.
CodeUnit codeUnit = CodeUnit.Load("Program.cs");
if (codeUnit != null)
    Log.WriteLine("File '" + codeUnit.Name + "' successfully loaded, parsed, resolved (except external references).");
Load a code fragment, parsing and resolving it
C#
// A code fragment can be a type or method declaration, or just a chunk of code.  Formatting is not that
// important, including newlines (although newlines - or the lack of them - will be preserved unless the
// code is specifically re-formatted).  Invalid code will produce parse errors.
const string fragment = "int sum = 0; for (int i = 1; i < 10; ++i) sum += i;";

// As in the LoadCodeUnit example, external references will not be resolved since there are no assembly references.
// See the LoadCodeUnits() example for how external references can be resolved.
CodeUnit codeUnit = CodeUnit.LoadFragment(fragment, "Fragment");
if (codeUnit != null)
    Log.WriteLine("Code fragment '" + codeUnit.Name + "' successfully parsed, resolved (except external references).");
Load multiple CodeUnits with resolving of external references
C#
// To load one or more CodeUnits with external references resolved, create a 'dummy' parent Project for the CodeUnits,
// and add any desired assembly references to it.
Project project = new Project("Miscellaneous Files", null);
CodeUnit codeUnit1 = project.AddFile("Program.cs");  // Add files like this
CodeUnit codeUnit2 = project.AddFile("MyVisitor.cs");
const string fragment = "using System; Console.WriteLine(\"TEST\");";
CodeUnit codeUnit3 = project.CreateCodeUnit(fragment, "Fragment");  // Add code fragments like this

// We want external references resolved in this case, so add assembly references and load their types
project.AddDefaultAssemblyReferences();  // Add commonly used assembly references
// Add additional assembly references like this, with an optional "hint path":
project.AddAssemblyReference("Nova.CodeDOM", "..\\Nova.CodeDOM.dll");
// You may also set 'project.ReferencePath' to a string of semi-colon separated search paths.

project.LoadReferencedAssembliesAndTypes();  // Load the referenced assemblies, and their public types
project.ParseAndResolveCodeUnits();          // Parse and resolve all code units in the project

// In this example, there is no Solution, so we can't benefit from it's single CodeAnnotations collection
// of all messages for all source files.  We could add a dummy Solution to the Project to get this, or look
// at the ListedAnnotations collection on each CodeUnit.  In this case, we'll just call a helper method on
// each CodeUnit that displays message counts along with any errors or warnings.
codeUnit1.LogMessageCounts(true);
codeUnit2.LogMessageCounts(true);
codeUnit3.LogMessageCounts(true);