I'm surprised by how many people don't know this trick...  but equally surprised by how obscure the UI is.

The Problem

Let's say you have a clever little bit of C# code you'd like to reuse, but it's something too trivial to warrant its building, supporting, and maintaining its own assembly.  Or perhaps the code is something proptrietary, and you'd like to obfuscate it as fully as possible -- which usually means not exposing it in any public types.  Or perhaps it's just a small set of compile-time constants that you'd like to bring into multiple assemblies.

As a trivially simple example, perhaps you get tired of specifying the same AssemblyCompany and AssemblyCopyright strings, over and over again, in all your projects?  Wouldn't it be nice to have a little two-line C# file tucked away somewhere, and include it by reference in all your projects?

[assembly: System.Reflection.AssemblyCompany("Arithex.com")]
[assembly: System.Reflection.AssemblyCopyright("© 2003 Shawn A. Van Ness. All rights reserved.")]

With C++ this is trivial -- you create a header file, and #include it from wherever you like.  But C# doesn't have a #include directive.  Or does it?

The Solution

No, it doesn't (sorry to tease ;-).  But Visual Studio .NET does offer a way to bring in C# code from a source file that's nowhere near the rest of the source files in your project directory -- it's not intra-file lexicographic inclusion, as in C++, but every C# source file can see every other C# source file in the build, so in practice there's not much difference!

Unfortunately, the UI to accomplish this task is pretty obscure -- which is probably why I run into so few developers who know about it.  It's so obscure, in fact, that I often find it easier to close VS and hack the .csproj file manually.  Here's what a <File> element might look like, for a C# project file (a .csproj file) that references a shared definition for my hypothetical AssemblyCompany and AssemblyCopyright strings, above:

   <File
      RelPath = "AssemblyCompanyAndCopyright.cs"
      Link = "..\..\AssemblyCompanyAndCopyright.cs"
      SubType = "Code"
      BuildAction = "Compile"
   />

Note that "RelPath" attribute is not, as you might think, a relative path to the file.  That would make sense!  Rather, it's the relative path of where the node will appear in the Solution Explorer treeview.  (This is the same "RelPath" attribute that you see on every other file in your C# project.)  The "Link" attribute is the interesting one -- that's the relative path to the actual file (relative to the .csproj file).  In Solution Explorer, the "linked' file will appear with an Explorer-style shortcut arrow emblazoned over its icon.

If you have some trepidation about hacking up your .csproj files, or if you absolutely, positively insist on using a mouse...  right-click your project in Solutions Explorer, and select Add Existing Item.  Browse to your shared C# source file, then click the unnoticeable little dropdown arrow next to the Open button.  See the ctxmenu item entitled "Link File"?  That's your man.

The Catch

(There's always a catch.)  For anything more complex than assembly-level attributes, one must think carefully about duplicating C# code across multiple assemblies.  Consider the following hypothetical SharedConstants.cs file...

using System;
namespace MyCompany {
internal class SharedConstants {

    public const string Hello = "Hello";
    public const string World = "World";
    }
}

This will produce a new, different type named MyCompany.SharedConstants in each and every assembly you "include" it in.  If the constants are large, or if the sanctity of SharedConstants' type-identity is important to you (imagine, perhaps, defining an enum this way, then later developing methods and properties which attempt to pass parameters of that type across assembly boundaries) then this approach may be undesirable -- or it may flat out break.

In that case, your only real option is to build a shared assembly which defines the constants (or enumeration values, etc), then ref that assembly in your other projects.  And that is, of course, what the founding fathers of .NET intended.