Странная ошибка компиляции, когда косвенно ссылаются на сборку, которая объявляет универсальный метод расширения с ограничением типа - PullRequest
2 голосов
/ 22 декабря 2011

Ну, для меня ясно, что название моего вопроса слишком сложное.Я просто попытался сделать это как можно более конкретным.Итак, я попытаюсь объяснить проблему лучше.

Контекст проблемы

Предположим, у нас есть три проекта .NET в решении.Основной проект представляет собой простое консольное приложение ApplicationAssembly .Этот проект имеет ссылку на другую управляемую библиотеку сборок DirectlyReferencedLibrary .В то же время DirectlyReferencedLibrary ссылается на IndirectlyUsedLibrary .

Итак, использование проекта выглядит так: ApplicationAssembly -> DirectlyReferencedLibrary -> IndirectlyUsedLibrary .

Обратите внимание, что ApplicationAssembly не использует напрямую ни один тип, объявленный IndirectlyUsedLibrary.Давайте также предположим, что все типы, объявленные в этих сборках, находятся в одном и том же пространстве имен.

Это решение компилируется и работает нормально.

Странная проблема

Проблема возникает, когда я вместеследующие условия:

  1. проект ApplicationAssembly использует выражения LINQ.Например, если есть вызов Select () для любого объекта перечислимого типа.
  2. DirectlyReferencedLibrary объявляет класс, который имеет универсальный метод расширения с ограничением типа.Ограничение типа говорит, что универсальный тип должен быть потомком класса из IndirectlyUsedLibrary .

Вот пример такого класса.

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.");
        }
    }
}

Когда я пытаюсь скомпилировать этот проект, я получаю следующую ошибку:

Ошибка Тип "Test.ProblemType" определен в сборке, на которую нет ссылок.Вы должны добавить ссылку на сборку "IndirectlyUsedLibrary, версия = 1.0.0.0, Culture = нейтральный, PublicKeyToken = null".C: \ Projects \ Test \ ApplicationAssembly \ Program.cs 22 13 ApplicationAssembly

Вопрос

Может кто-нибудь помочь мне понять, почему это так?

PS

Я сделал крошечное решение для расследования. Если вы любезно поможете мне, вы сможете взять архивное решение здесь

PPS

Извините за мой плохой английский.

UPD1

Еще одна странная вещь заключается в том, что различные вызовы метода LINQ могут вызывать или не вызывать ошибку времени компиляции:

// 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);

Ответы [ 3 ]

14 голосов
/ 22 декабря 2011

Может кто-нибудь помочь мне понять, почему это так?

Компилятор C # разумно полагает, что транзитивное закрытие ссылочных сборок доступно во время компиляции. Он не имеет какой-либо продвинутой логики, которая объясняет, что ему определенно нужно, может понадобиться, может не понадобиться или определенно не нужно знать, чтобы решить все проблемы при анализе типов, которые ваша программа собирается бросить на это. , Если вы ссылаетесь на сборку прямо или косвенно, компилятор предполагает, что там может быть информация о типе, которая ему нужна.

Кроме того, если у вас нет набора ссылочных сборок во время компиляции , тогда чего ожидать, что пользователи получат их во время выполнения? Представляется разумным ожидать, что среда времени компиляции имеет как минимум набор сборок, которые потребуются во время выполнения.

Я не хочу этого делать.

Мы все должны делать то, чего не хотим делать в жизни.

2 голосов
/ 22 декабря 2011

Я думаю, что вы знали это, но поскольку тип ProblemType определен в "IndirectlyUsedLibrary", но является обязательным определением для метода расширения Magic, на него нужно сослаться, чтобы он был доступен во время компиляции.

Что касается "почему" ... Что ж, компилятору нужно знать детали того, что он компилирует, не так ли?Для меня имеет смысл, что компилятору требуется тот же минимальный набор ссылок времени компиляции, который требуется во время выполнения ...

1 голос
/ 22 декабря 2011

У вас не будет ошибки, если вы будете использовать разные пространства имен для библиотек.Действительно странно использовать одно и то же пространство имен в разных библиотеках.

Похоже, компилятор начинает сканировать ваше пространство имен Test на наличие расширений, как только вы впервые его используете.Следовательно, ссылка обязательна.

...