Weird compilation error when indirectly refer to an assembly that declares a generic extension method with type restriction

StackOverflow https://stackoverflow.com/questions/8597486

Question

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.

Problem context

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.

Weird problem

The problem occurs when I have together the following conditions:

  1. the ApplicationAssembly project has usages of LINQ expressions. For example, if there is the invocation of Select() on any object of enumerable type.
  2. The DirectlyReferencedLibrary declares a class which has a generic extension method with a type restriction. The type restriction says that the generic type must be a descendant of a class from the IndirectlyUsedLibrary.

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

Question

Can anyone help me to understand why is it so?

P.S.

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

P.P.S.

Sorry for my poor English.

UPD1

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);
Was it helpful?

Solution

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.

OTHER TIPS

I think you knew this, but because the type ProblemType is defined in the "IndirectlyUsedLibrary" but is a required definition for the Magic extension method it must be referenced to be available at compile time.

As to "why"... Well, the compiler needs to know details about what it's compiling doesn't it? It makes sense to me that the compiler require the same minimum set of compile time references that it requires at run time...

You'll not have an error if you use different namespaces for libraries. It's really wierd to use same namespace across different libraries.

Looks like compiler starts scanning your Test namespace for extensions once you first time use any. Hence the reference is required.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top