2012-04-18 15 views
11

Tengo un conjunto A que define una interfaz con algunas sobrecargas:¿Por qué (a veces) tengo que hacer referencia a los ensamblados a los que hace referencia el ensamblaje al que hago referencia?

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

... y un conjunto B que hace referencia a A (el binario, no en el proyecto) y llama a una de las sobrecargas:

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

Para ser precisos, se llama a la sobrecarga del método System.Windows.PointInverseTransform, porque ese es el tipo de la propiedad Location en e.

Pero cuando construyo B en el IDE me sale: CS0012

de error: El tipo 'System.Drawing.Point' se define en una asamblea que no se hace referencia. Debe agregar una referencia al ensamblado 'System.Drawing, Version = 4.0.0.0, Culture = neutral, PublicKeyToken = b03f5f7f11d50a3a'.

a pesar de que ni siquiera es la sobrecarga que estoy llamando. Cuando comente la línea donde se llama al método InverseTransform sobrecargado, se compila bien aunque sigo instanciando un objeto del tipo ITransform.

¿Por qué? ¿Y hay una manera de solucionar esto sin tener que agregar una referencia a System.Drawing en todas partes?

+0

Por curiosidad, ¿podría cambiar el nombre de la última sobrecarga a 'InverseTransform2' y volver a intentarlo? No sé la respuesta, pero me pregunto si tiene algo que ver con la resolución de sobrecarga. – dasblinkenlight

+0

¿Es 'e.Location' específicamente un objeto' System.Windows.Point' u otra clase que se deriva de 'System.Windows.Point'? –

+0

@dasblinkenlight: sí, tiene que ver con la resolución de sobrecarga, usar diferentes nombres de métodos lo resuelve, pero no quiero cambiar la interfaz – mtijn

Respuesta

12

El compilador necesita saber qué es System.Drawing.Point para demostrar que no es la sobrecarga correcta (por ejemplo, si tiene una conversión implícita).

+0

pero incluso si específicamente (re) echo a System.Windows.Point, aún no se compila. ¿por qué probar que * no es * un System.Drawing.Point cuando claramente * es * un System.Windows.Point? – mtijn

+0

@mtijn: Ha definido la interfaz de esa manera: espera un System.Drawing.Point: 'System.Drawing.Point InverseTransform (System.Drawing.Point point);' Incluso si tiene un molde, aún necesita saber qué es un System.Drawing.Point. – Skalli

+0

¿Crees que esta es una situación en la que el compilador podría ser más inteligente? Si se sabe que 'e.Location' es' System.Windows.Point' (y no una derivación de eso), entonces no hay forma de que 'System.Drawing.Point' sea la sobrecarga más específica. Podría pasar por alto esa parte de la resolución de sobrecarga. –

4

Ese método hace uso de algo definido en System.Drawing. Si lo descomenta, entonces ese ensamblaje ya no intentará usar System.Drawing; por lo tanto, no hay requisito.

Piénselo de esta manera, cuando se vaya a realizar su acción .NET dice que está bien, estoy haciendo una llamada a este tipo definido en este conjunto y busco el código apropiado para ejecutar. No puede encontrarlo, así que vomita sus manos y dice: "Me rindo, dime dónde está".

Simplemente hágalo como un hábito de hacer referencia a cada archivo DLL que pueda utilizar.

+0

no, llama a la sobrecarga System.Windows.Point del método y no a System.Drawing.Point one – mtijn

+1

@mtijn: lo necesita para la resolución de sobrecarga. Ver mi edición – SLaks

+1

SÍ como dice @SLaks, todavía lo estás usando. – scottheckel

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()); 
     } 
    } 
} 

En lugar de lo que no se puede hacer contando ...

Una forma de solucionar este problema que supondría la introducción de IPOINT Transform (IPOINT x) como el único método en la interfaz, junto con interfaz IPOINT . Esto significaría que System.Drawing también debería cumplir con su IPoint.

Si desea ese nivel de desacoplamiento, le viene a la mente la palabra clave dinámica, ya que no puede lograr que Drawing.Point implemente una interfaz después de los hechos. Solo asegúrate de tener una gran cobertura de prueba de unidad en esta parte del código, y espera que funcione un poco más lento.

De esta manera, solo tendrías que hacer referencia a System.Drawing solo en ensamblajes donde realmente lo estés usando.

EDIT Reflector dice que la firma de System.Drawing.Punto es

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

no pensó en usar dinámico todavía ... Intenté 'dynamic transform = ...' en lugar de ' var transform = ... 'y eso parece compilar pero aún no lo he ejecutado. pero si estuviera cambiando la interfaz de todos modos, podría haber logrado el mismo efecto con los genéricos, ¿verdad? – mtijn

+0

Si la perforación es su problema, intente utilizar FastMember. Si cree que necesita soporte de compilador, vea la respuesta de SLaks. – GregC

+1

Estoy de acuerdo en que sería bueno si el compilador no le pidiera que agregue una referencia a menos que el tipo tenga que ser compilado en la IL. Esto reduciría el ruido a expensas de hacer un proceso de compilación un poco más implícito. – GregC

0

Para resolver esto (y siempre y cuando no tiene demasiado llamadas para envolver etc.)
puede simplemente definir una envoltura de extensión para que el 'punto' llamar sólo está utilizando, por ejemplo,

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

... alimentar ese lib (donde la extensión es), la referencia System.Drawing
(y para evitar tener que añadir su 'lib envoltorio' en todas partes, que sería contrario al propósito, sólo hay que poner en una lib común a la que ya ha hecho referencia, relacionada con el problema. Mejor es si es parte de la lib 'fuente' pero diciendo en caso de que no pueda cambiar eso) ...

y llámelo luego a través de MyInverseTransform.

2

La única diferencia entre las sobrecargas son los tipos. Es por eso que el compilador no puede distinguir qué sobrecarga está usando sin mirar el tipo.

Dado que el ensamblado de ejecución no hace referencia al tipo, el compilador no conoce el tipo y necesita una referencia directa al ensamblaje que contiene la definición de tipo.

Me encontré con este problema yo mismo y no quería agregar una referencia directa al conjunto que contiene el tipo. Simplemente agregué un argumento (booleano) a uno de los métodos para que ya no sean sobrecargas el uno del otro. El compilador entendió la diferencia entre los métodos, incluso si tienen el mismo nombre, porque tienen una cantidad diferente de argumentos. Ya no es necesaria una referencia al ensamblaje que contiene el tipo. Sé que no es una solución ideal, pero no pude encontrar otra solución ya que mi método era un constructor, así que no pude cambiar su firma de ninguna otra manera.

Cuestiones relacionadas