12

我有一个程序集 A 定义了一个带有一些重载的接口:

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

...以及引用 A(二进制文件,而不是项目)并调用其中一个重载的程序集 B:

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

但是当我在 IDE 中构建 B 时,我得到:

错误 CS0012:“System.Drawing.Point”类型在未引用的程序集中定义。您必须添加对程序集“System.Drawing,Version=4.0.0.0,Culture=neutral,PublicKeyToken=b03f5f7f11d50a3a”的引用。

即使这甚至不是我打电话的超载。当我注释掉InverseTransform调用重载方法的行时,即使我仍在实例化类型的对象,它也可以正常构建ITransform

为什么?有没有办法解决这个问题而不必在System.Drawing任何地方添加引用?

4

5 回答 5

12

编译器需要知道 aSystem.Drawing.Point是什么,以证明它不是正确的重载(例如,如果它有隐式转换)。

于 2012-04-18T13:47:46.463 回答
4

该方法利用System.Drawing. 如果您取消注释,则该程序集将不再尝试使用System.Drawing; 因此,没有要求。

这样想,当你去执行你的动作时,.NET 说好的,我正在调用这个程序集中定义的这个人,并寻找合适的代码来执行。它找不到它,所以它举起双手说我放弃了,你告诉我它在哪里。

只需养成引用您可能使用的每个 DLL 的习惯即可。

于 2012-04-18T13:47:21.190 回答
2
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 Transform(IPoint x) 作为接口中的唯一方法,以及 IPoint 接口。这意味着 System.Drawing 也必须遵守您的 IPoint。

如果您想要那种级别的解耦,那么您会想到动态关键字,因为您无法让 Drawing.Point 事后实现接口。只要确保对这部分代码有非常好的单元测试覆盖率,并期望它的执行速度会慢一些。

这样,您只需在实际使用它的程序集中引用 System.Drawing。

EDIT Reflector 说 System.Drawing.Point 的签名是

[Serializable, StructLayout(LayoutKind.Sequential), TypeConverter(typeof(PointConverter)), ComVisible(true)]
public struct Point { }
于 2012-04-18T14:01:04.813 回答
2

重载之间的唯一区别是类型。这就是为什么编译器无法在不查看类型的情况下区分您正在使用的重载。

由于执行程序集不引用类型,编译器不知道类型,需要直接引用包含类型定义的程序集。

我自己遇到了这个问题,不想添加对包含该类型的程序集的直接引用。我只是向其中一个方法添加了一个参数(布尔值),因此它们不再是彼此的重载。然后编译器理解了这些方法之间的区别,即使它们具有相同的名称,因为它们具有不同数量的参数。它不再需要对包含该类型的程序集的引用。我知道这不是一个理想的解决方案,但我找不到另一个解决方案,因为我的方法是一个构造函数,所以我无法以任何其他方式更改它的签名。

于 2015-08-20T17:36:10.950 回答
0

要解决这个问题(并且假设您没有太多的调用来包装等)
,您可以简单地为您仅使用的“点”调用定义一个扩展包装器,例如

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

...为该库(扩展名所在的位置)提供 System.Drawing 引用
(并避免必须在任何地方添加“包装库”,因为这会破坏目的,只需将其放入您已经引用过的一些通用库中,与问题有关。最好是“源”库的一部分,但如果你不能改变它)......

然后通过调用它MyInverseTransform

于 2012-04-18T17:41:05.307 回答