2012-04-18 12 views
11

Ho un assembly A, che definisce un'interfaccia con alcuni sovraccarichi:Perché a volte (a volte) devo fare riferimento agli assiemi a cui fa riferimento l'assieme riferimento?

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

... e un gruppo B che fa riferimento A (binario, non il progetto) e chiama uno dei sovraccarichi:

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

Per essere precisi, chiama il System.Windows.Point overload del metodo InverseTransform, perché questo è il tipo di proprietà Location in e.

Ma quando ho costruire B nell'IDE ottengo:

errore CS0012: Il tipo 'System.Drawing.Point' è definito in un assembly che non viene fatto riferimento. È necessario aggiungere un riferimento all'assembly 'System.Drawing, Version = 4.0.0.0, Culture = neutral, PublicKeyToken = b03f5f7f11d50a3a'.

anche se questo non è nemmeno il sovraccarico che sto chiamando. Quando commento la riga in cui viene chiamato il metodo sovraccarico InverseTransform, esso funziona bene anche se sto ancora creando un'istanza di un oggetto di tipo ITransform.

Perché? E c'è un modo per risolvere questo problema senza dover aggiungere un riferimento a System.Drawing ovunque?

+0

Per curiosità, è possibile rinominare l'ultimo sovraccarico in 'InverseTransform2' e riprovare? Non conosco la risposta, ma mi chiedo se abbia qualcosa a che fare con la risoluzione del sovraccarico. – dasblinkenlight

+0

È 'e.Location' specificamente un oggetto' System.Windows.Point' o un'altra classe che deriva da 'System.Windows.Point'? –

+0

@dasblinkenlight: sì ha a che fare con la risoluzione di sovraccarico, usando nomi di metodi diversi lo risolve ma non voglio cambiare l'interfaccia – mtijn

risposta

12

Il compilatore deve sapere cos'è un System.Drawing.Point per dimostrare che non è il sovraccarico corretto (ad esempio, se ha una conversione implicita).

+0

ma anche se scrivo (ri) espressamente in System.Windows.Point, esso non si compila ancora. perché dimostrare che * non è * un System.Drawing.Point quando è chiaramente * un * System.Windows.Point? – mtijn

+0

@mtijn: L'interfaccia è stata definita in questo modo: Si aspetta un System.Drawing.Point: 'System.Drawing.Point InverseTransform (punto System.Drawing.Point);' Anche se si dispone di un cast, è necessario sapere cos'è un System.Drawing.Point. – Skalli

+0

Pensi che questa sia una situazione in cui il compilatore potrebbe essere più intelligente? Se 'e.Location' è noto per essere un' System.Windows.Point' (e non una derivazione da quello), allora non c'è modo che System.Drawing.Point' possa essere il sovraccarico più specifico. Potrebbe presumibilmente saltare quella parte della risoluzione di sovraccarico. –

4

Questo metodo utilizza qualcosa definito in System.Drawing. Se si disapprova, tale assembly non tenterà più di utilizzare System.Drawing; quindi, nessun requisito.

Pensateci in questo modo, quando andrete a svolgere la vostra azione. NET dice ok Sto facendo una chiamata a questo tizio definito in questo assembly e cerco il codice appropriato da eseguire. Non riesce a trovarlo, quindi getta le sue mani e dice che mi arrendo e dimmi dov'è.

Basta prendere l'abitudine di fare riferimento a tutte le DLL che si potrebbero potenzialmente utilizzare.

+0

no, chiama il sovraccarico System.Windows.Point del metodo e non System.Drawing.Point uno – mtijn

+1

@mtijn: ne ha bisogno per la risoluzione di sovraccarico. Vedi la mia modifica. – SLaks

+1

Sì, come dice @SLaks, lo stai ancora utilizzando. – 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()); 
     } 
    } 
} 

Invece di ciò che non si può fare dicendo ...

Un modo per risolvere questo comporterebbe l'introduzione di IPoint Transform (IPoint x) come l'unico metodo nell'interfaccia, insieme all'interfaccia IPoint . Ciò significherebbe che System.Drawing dovrebbe essere conforme anche al tuo IPoint.

Se si desidera tale livello di disaccoppiamento, viene in mente una parola chiave dinamica, poiché non è possibile ottenere Drawing.Point per implementare un'interfaccia dopo il fatto. Assicurati solo di avere una copertura di test unitaria davvero eccezionale su questa parte di codice, e aspettati che funzioni un po 'più lentamente.

In questo modo, è sufficiente fare riferimento a System.Drawing solo negli assiemi in cui lo si sta effettivamente utilizzando.

EDIT Riflettore che indica la firma di System.Drawing.Point è

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

non pensava di utilizzare la dinamica ancora .. Ho provato 'dynamic transform = ...' invece di ' var transform = ... 'e sembra compilare ma non l'ho ancora eseguito. ma se dovessi cambiare l'interfaccia comunque avrei potuto ottenere lo stesso effetto con i generici, giusto? – mtijn

+0

Se perf è la tua preoccupazione, prova a utilizzare FastMember. Se ritieni di aver bisogno del supporto del compilatore, consulta la risposta di SLaks. – GregC

+1

Sono d'accordo che sarebbe bene se il compilatore non ti chiedesse di aggiungere un riferimento a meno che il tipo non debba essere compilato nell'IL. Ciò ridurrebbe il rumore a scapito di rendere un processo di compilazione un po 'più implicito. – GregC

0

Per risolvere questo (e fornendo non avete troppo chiamate per avvolgere ecc)
si può semplicemente definire un involucro estensione per che 'Point' chiamata si sta utilizzando solo per esempio

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

... alimentare che lib (dove l'estensione è) il riferimento System.Drawing
(e per evitare di dover aggiungere la 'involucro lib' dappertutto come sarebbe vanificato l'obiettivo, appena messo in un po 'di libbia comune a cui hai già fatto riferimento, correlata al problema. La migliore è se parte della lib' sorgente 'ma dicendo nel caso non sia possibile cambiarla ...

e chiamarlo poi tramite MyInverseTransform.

2

L'unica differenza tra i sovraccarichi sono i tipi. Questo è il motivo per cui il compilatore non può distinguere quale sovraccarico stai usando senza guardare il tipo.

Poiché il tipo non fa riferimento all'assembly in esecuzione, il compilatore non conosce il tipo e richiede un riferimento diretto all'assembly che contiene la definizione del tipo.

Ho eseguito personalmente questo problema e non desideravo aggiungere un riferimento diretto all'assembly che contiene il tipo. Ho semplicemente aggiunto un argomento (booleano) a uno dei metodi in modo che non siano più sovraccarichi l'uno dell'altro. Il compilatore ha quindi compreso la differenza tra i metodi, anche se hanno lo stesso nome, perché hanno una quantità diversa di argomenti. Non è più necessario un riferimento all'assembly che contiene il tipo. So che non è una soluzione ideale, ma non sono riuscito a trovare un'altra soluzione in quanto il mio metodo era un costruttore quindi non potevo cambiare la sua firma in nessun altro modo.

Problemi correlati