12

I have an assembly A that defines an interface with some overloads:

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

...and an assembly B that references A (the binary, not the project) and calls one of the overloads:

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

To be precise, it calls the System.Windows.Point overload of the InverseTransform method, because that is the type of the property Location in e.

But when I build B in the IDE I get:

error CS0012: The type 'System.Drawing.Point' is defined in an assembly that is not referenced. You must add a reference to assembly 'System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'.

even though that's not even the overload I am calling. When I comment out the line where the overloaded method InverseTransform is called, it builds fine even though I'm still instantiating an object of type ITransform.

Why? And is there a way to fix this without having to add a reference to System.Drawing everywhere?

4

5 に答える 5

12

The compiler needs to know what a System.Drawing.Point is in order to prove that it's not the correct overload (eg, if it has an implicit conversion).

于 2012-04-18T13:47:46.463 に答える
4

That method makes use of something defined in System.Drawing. If you uncomment it then that assembly no longer will by trying to use System.Drawing; hence, no requirement.

Think of it this way, when you go off to perform your action .NET says ok I'm making a call to this guy defined in this assembly and looks for the appropriate code to execute. It can't find it so it throws up it's hands and says I give up you tell me where it is.

Just make it a habit of referencing every DLL you might potentially use.

于 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インターフェイスと一緒にIPoint Transform(IPoint x)をインターフェイスの唯一のメソッドとして導入することを必要とします。これは、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

The only difference between overloads are the types. That is why the compiler cannot distinguish which overload you're using without looking at the type.

Since the type is not referenced by the executing assembly, the compiler doesn't know the type and needs a direct reference to the assembly containing the type definition.

I ran in this issue myself and didn't want to add a direct reference to the assembly containing the type. I simply added an argument (boolean) to one of the methods so they are no longer overloads of eachother. The compiler then understood the difference between the methods, even if they have the same name, because they have a different amount of arguments. It no longer needed a reference to the assembly containing the type. I know it's not an ideal solution, but I couldn't find another solution as my method was a constructor so I couldn't change its signature in any other way.

于 2015-08-20T17:36:10.950 に答える
0

To resolve this (and providing you don't have too much calls to wrap etc.)
you could simply define an extension wrapper for that 'Point' call you're only using e.g.

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

...feed that lib (where the extension is) the System.Drawing reference
(and to avoid having to add your 'wrapper lib' everywhere as that would defeat the purpose, just put it in some common lib which you have referenced already, related to the problem. Best is if part of the 'source' lib but saying in case you cannot change that)...

and call it then via MyInverseTransform instead.

于 2012-04-18T17:41:05.307 に答える