2

Overview

Debugging an interesting bug, I stripped down a solution to its bare bones in an attempt to isolate it. The issue manifests itself with a classic build error (assembly not referenced).

What's interesting is that no types from the assembly in question are used in the assembly that cannot be built. Moving using statements and removing CLS compliance attributes make the error disappear, implying that an obscure symbol visibility rule is in effect (probably).

Code

Mandelbug/
|-- Mandelbug.sln
`-- src
    |-- Bar
    |   |-- Bar.csproj
    |   `-- Beta.cs
    |-- Baz
    |   |-- Baz.csproj
    |   |-- Gamma.cs
    |   `-- Properties
    |       `-- AssemblyInfo.cs
    `-- Foo
        |-- Alpha.cs
        `-- Foo.csproj

Except for the project (csproj) files, the entire codebase is shown here, line-by-line.

Foo/Alpha.cs

namespace Foo {
    public class Alpha : Bar.Beta { }
}

Bar/Beta.cs

namespace Bar {
    public class Beta { }
}

Baz/Gamma.cs

namespace Foo {
    using System;
    public class Gamma { }
}

Baz/Properties/AssemblyInfo.cs

[assembly: System.CLSCompliant(true)]

Dependencies

enter image description here

All projects reference System and System.Core.
Baz references Foo.
Foo references Bar.

Foo.Alpha needs the dependency to inherit from Bar.Beta.
Baz.Gamma needs the dependency for other types in Foo in the real solution (unrelated to Alpha). None are used in this stripped down solution, yet the issue still appears.

Compilation error

Description: The type 'Bar.Beta' is defined in an assembly that is not referenced. You must add a reference to assembly 'Bar, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'.
File: src\Baz\Gamma.cs
Line: 1
Column: 11
Project: Baz

Behavior

The problem disappears when:

  1. Placing the using statement in Gamma outside the Foo namespace block.
  2. Removing the CLSCompliant attribute for the Baz assembly.
  3. Alpha does not inherit from Beta (even if Foo still references Bar and Alpha still uses Beta in other ways, for example by composing it).
  4. Foo is out of reach from Gamma (for example by changing Gamma's namespace to Baz).
  5. A reference to Bar is added in Baz.

It doesn't matter if the other projects are CLS compliant or not. In the real solution they are.
The target framework doesn't seem to influence that behavior.
It doesn't matter what namespace we import in the Gamma.cs namespace block, we're writing using System; here, but it could be anything. Removing all using statements (or placing them outside the namespace block) makes the problem go away, as mentioned above.

Questions

  1. What CLS rule affects that behavior?
  2. Why does placing the using statement inside or outside the namespace block affects that behavior?
  3. This is not just a curiosity, we actually have a project with such a transitive dependency -- should we add the reference to Bar even though it doesn't make sense? (We're not using the Alpha inherited type.)

Notes

I know the compiler is never wrong, but it still looks like some serious voodoo when you don't know what's going on (especially the using statement placement thing). I've skimmed the I.11 section of ECMA-335 (CLI) which contains a reference of CLS rules, but I can't pinpoint which one is the one I should understand but obviously don't.

Should the issue not be obvious, you should be able to reproduce it consistently by simply copying the code verbatim in empty C# projects and adding the same references.

Jester
  • 56,577
  • 4
  • 81
  • 125
tne
  • 7,071
  • 2
  • 45
  • 68
  • I can sort of see how it happened, nothing to nail to a wall. File a bug report at connect.microsoft.com. And do consider removing the attribute, it stopped making sense 9 years ago. – Hans Passant Jul 11 '14 at 18:27
  • @HansPassant: Thanks, I'll probably do that. Still, although I'm not one of them, I'd imagine many people might not agree on your statement about CLS compliance, especially when it comes to libraries. Also, I think I've found a [duplicate](http://stackoverflow.com/q/1254078) - I'll investigate in details tomorrow and properly mark it as such if it's right. The answers there don't seem too conclusive at first glance though, I hope I'm wrong. – tne Jul 13 '14 at 12:55
  • [Filed](https://connect.microsoft.com/VisualStudio/feedback/details/920175/cls-compliance-and-build-time-transitive-dependency-requirements). – tne Jul 14 '14 at 08:39
  • Fixed in Roslyn (see bug report). – tne Jul 24 '14 at 07:43

0 Answers0