Well, it's clear for me that the title of my question is too complicated. I just tried to make it as specific as possible. So, I'll try to explain the problem better.
Let's assume we have three .NET projects in a solution. The main project is a simple console application ApplicationAssembly. This project has a reference to another managed assembly library DirectlyReferencedLibrary. At the same time DirectlyReferencedLibrary refers to IndirectlyUsedLibrary.
So, the project usages looks like that: ApplicationAssembly --> DirectlyReferencedLibrary --> IndirectlyUsedLibrary.
Notice that ApplicationAssembly doesn't use directly any type declared IndirectlyUsedLibrary. Let's also assume that all types declared in these assemblies reside in the same namespace.
This solution compiles and works fine.
The problem occurs when I have together the following conditions:
Here is the example of a such class.
using System;
namespace Test
{
public static class UnUsedType
{
// It's a generic extension method with a type restriction.
public static void Magic<T>(this T @this)
// It's a type restriction that uses a type from the IndirectlyUsedLibrary.
where T : ProblemType
{
Console.WriteLine("I do nothing actually.");
}
}
}
When I try to compile this project, I get the following error:
Error The type 'Test.ProblemType' is defined in an assembly that is not referenced. You must add a reference to assembly 'IndirectlyUsedLibrary, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'. C:\Projects\Test\ApplicationAssembly\Program.cs 22 13 ApplicationAssembly
Can anyone help me to understand why is it so?
I've made a tiny solution for investigation. If you are so kind to help me, you will be able to take an archived solution here
Sorry for my poor English.
Another strange thing is that different invocations of the LINQ method may or may not produce the compile time error:
// Ok. Let's do some work using LINQ we love so much!
var strings = new[] { "aaa", "bbb", "ccc" };
Func<string, object> converter = item => (object) item;
// The following line makes problems.
var asObjects1 = strings.Select(converter);
// Everything is OK if we use the following line:
var asObjects2 = Enumerable.Select(strings, converter);
Can anyone help me to understand why is it so?
The C# compiler has the reasonable expectation that the transitive closure of the referenced assemblies is available at compile time. It does not have any kind of advanced logic that reasons about what it definitely needs, might need, might not need, or definitely does not need to know in order to solve all the problems in type analysis that your program is going to throw at it. If you reference an assembly directly or indirectly, the compiler assumes that there might be type information in there that it needs.
Also, if you don't have the set of referenced assemblies at compile time then what expectation is there that users will have them at runtime? It seems reasonable to expect that the compile time environment has at least the set of assemblies that are going to be required at runtime.
I don't want to do it.
We all have to do things we don't want to do in life.