Почему я (иногда)должен ссылаться на сборки, на которые ссылается сборка I?

у меня есть сборка, которая определяет интерфейс с некоторыми перегрузками:

public interface ITransform
{
    Point InverseTransform(Point point);
    Rect InverseTransform(Rect value);
    System.Drawing.Point InverseTransform(System.Drawing.Point point);
}

...и сборка B, которая ссылается на A (двоичный файл, а не проект) и вызывает одну из перегрузок:

var transform =
    (other.Source.TransformToDisplay != null &&
    other.Source.TransformToDisplay.Valid) ?
    other.Source.TransformToDisplay : null;
if (transform != null)
{
    e.Location = transform.InverseTransform(e.Location);
}

чтобы быть точным, он называет System.Windows.Point перегрузка InverseTransform метод, потому что это тип жилья Location на e.

но когда я строю B в IDE, я получаю:

ошибка CS0012: тип - Система.Рисунок.Точка ' определяется в сборке, на которую нет ссылки. Необходимо добавить ссылку на систему assembly.Рисунок, версия=4.0.0.0, культура=нейтральная, PublicKeyToken=b03f5f7f11d50a3a'.

хотя это даже не перегрузка, которую я вызываю. Когда я комментирую строку, где перегруженный метод InverseTransform вызывается, он отлично строится, хотя я все еще создаю экземпляр объекта типа ITransform.

почему? И есть ли способ исправить это без необходимо добавить ссылку на System.Drawing везде?

5 ответов


компилятор должен знать, что такое System.Drawing.Point чтобы доказать, что это не правильная перегрузка (например, если она имеет неявное преобразование).


этот метод использует что-то определенное в System.Drawing. Если вы раскомментируете его, то эта сборка больше не будет пытаться использовать System.Drawing; следовательно, никаких требований.

подумайте об этом таким образом, когда вы уходите, чтобы выполнить свое действие .NET говорит ок, я делаю вызов этому парню, определенному в этой сборке, и ищет соответствующий код для выполнения. Он не может найти его, поэтому он поднимает руки и говорит, что я сдаюсь, ты говоришь мне, где он.

просто сделайте это привычкой ссылка на каждую DLL, которую вы потенциально можете использовать.


namespace ClassLibrary1
{
   public interface ITransform
   {
      dynamic InverseTransform(dynamic point);
   }
}

using ClassLibrary1;
using Moq;
namespace ConsoleApplication9
{
   interface IPoint { }
   class Point : IPoint { }

   class Program
   {
      static void Main(string[] args)
      {
         var transform = new Mock<ITransform>();
         IPoint x = transform.Object.InverseTransform(new Point());
      }
   }
}

вместо того, чтобы сказать вам, что вы не можете сделать...

способ исправить это повлечет за собой введение преобразования IPoint (IPoint x) в качестве единственного метода в вашем интерфейсе вместе с интерфейсом IPoint. Это означало бы такую систему.Рисование также должно соответствовать вашему IPoint.

Если вы хотите, чтобы этот уровень развязки, динамическое ключевое слово приходит на ум, так как вы не можете получить рисунок.Точки для реализации интерфейса постфактум. Просто убедитесь, что действительно большой охват модульного теста на этой части кода и ожидать, что он будет работать несколько медленнее.

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

редактировать рефлектор говорит что подпись системы.Рисунок.Точка

[Serializable, StructLayout(LayoutKind.Sequential), TypeConverter(typeof(PointConverter)), ComVisible(true)]
public struct Point { }

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

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

Я сам запустил эту проблему и не хотел добавлять прямую ссылку на сборку, содержащую тип. Я просто добавил аргумент (boolean) для одного из методов, чтобы они больше не перегружали друг друга. Затем компилятор понял разницу между методами, даже если они имеют одно и то же имя, потому что у них разное количество аргументов. Она больше не нужна ссылка на сборку, содержащую тип. Я знаю, что это не идеальное решение, но я не мог найти другое решение, поскольку мой метод был конструктором, поэтому я не мог изменить его подпись каким-либо другим способом.


чтобы решить эту проблему (и при условии, что у вас не слишком много вызовов для обертывания и т. д.)
вы можете просто определить оболочку расширения для этого "точечного" вызова, который вы используете, например,

public static Point MyInverseTransform(this ITransform mytransform, Point point)
{
    return mytransform.InverseTransform(point);
}

...передайте этот lib (где расширение) системе.Ссылка на чертеж
(и чтобы избежать необходимости добавлять "обертку lib" везде, так как это приведет к поражению цели, просто поместите ее в некоторую общую lib, на которую вы уже ссылались, связанную с проблемой. Лучше всего, если часть "источник" lib, но говорит, Если вы не можете это изменить)...

и вызовите его через MyInverseTransform вместо.