为什么我(有时)必须引用我引用的程序集引用的程序集?

时间:2012-04-18 13:45:28

标签: c# visual-studio-2010 c#-4.0 dependencies .net-assembly

我有一个程序集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的引用?

5 个答案:

答案 0 :(得分:12)

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

答案 1 :(得分:4)

该方法使用System.Drawing中定义的内容。如果您取消注释,那么该程序集将不再尝试使用System.Drawing;因此,没有要求。

以这种方式思考,当你开始执行你的行动.NET说好的我正在调用这个程序集中定义的这个人,并寻找适当的代码来执行。它找不到它所以它抛出它的手并说我放弃你告诉我它在哪里。

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

答案 2 :(得分: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。

编辑 Reflector说System.Drawing.Point的签名是

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

答案 3 :(得分:2)

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

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

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

答案 4 :(得分:0)

要解决这个问题(并且你没有太多的电话来换行等) 你可以简单地为那个'Point'调用定义一个扩展包装器,你只使用例如

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

...提供lib(扩展名为)System.Drawing引用
(并且为了避免必须在任何地方添加你的'包装器lib',因为这会破坏目的,只需将它放在你已经引用的一些常见的lib中,与问题相关。最好是'源'lib的一部分但是说如果你不能改变那个)......

然后通过MyInverseTransform来调用它。