2016-07-13 89 views
5

ho un problema stupido, ho bisogno di implementare in F # di classe l'interfaccia che sono seguente metodo:F # implementazione di metodo di interfaccia con il tipo di vincolo

public interface IMyInterface 
{ 
    T MyMethod<T>() where T : class; 
} 

E mi sto lottando farlo in F #. Ho provato diversi modi. Ma il problema è che un oggetto di tipo T deve essere restituito. Null non viene accettata:

type public Implementation() = 
    interface IMyInterface with 
     member this.MyMethod<'T when 'T : not struct>() = null 

Errore: Il membro 'myMethod < 'T quando 'T: Non struct>: unit -> un' quando un': non struct e' una: null non ha la tipo corretto per sovrascrivere il metodo astratto corrispondente. La firma richiesta è 'MyMethod <' T quando 'T: Non struct>: unit ->' T quando 'T: Non struct'

Così ho cercato di mettere T come argomento alla classe, ma ancora nessuna ho finito con l'errore:

type public Implementation(data : 'T when 'T : not struct) = 
    interface IMyInterface with 
     member this.MyMethod<'T when 'T : not struct>() = data 

errore: il membro 'myMethod <' T quando 'T: non struct>: unit ->' T quando 'T: non struct' non ha il tipo corretto di ignorare il metodo astratto corrispondente.

Grazie per l'aiuto.

risposta

6

Invece di tornare null (che viene dedotto di avere un certo tipo 'a, controllare con il ritorno null :?> 'T) è possibile utilizzare

type public Implementation() = 
    interface IMyInterface with 
     member __.MyMethod<'T when 'T : not struct>() = Unchecked.defaultof<'T> 

preferisco __ sopra this quando non è utilizzato.

TL; DR;

Il vincolo class in C# include implicitamente null. Purtroppo specificando che in F # non è consentito:

member __.MyMethod<'T when 'T : not struct and 'T : null>() = Unchecked.defaultof<'T> 

risultati in:

The member 'MyMethod<'T when 'T : not struct and 'T : null> : unit -> 'T when 'T : not struct and 'T : null' does not have the correct type to override the corresponding abstract method. The required signature is 'MyMethod<'T when 'T : not struct> : unit -> 'T when 'T : not struct'.

Ma poi, utilizzando le classi e interfacce come questi cross-language richiede una particolare attenzione in ogni modo, perché C# e il CLR permettono null valori mentre F # no.

per il confronto con null migliore sovraccarico F # isNull (vedi questo answer):

let inline isNull (x:^T when ^T : not struct) = obj.ReferenceEquals (x, null) 

a meno che il vostro tipo permette null quando è possibile utilizzare standard di isNull:

[<AllowNullLiteral>] 
type Foo() = 
    member __.Bar() =() 

(Implementation() :> IMyInterface).MyMethod<Foo>() |> isNull // true 
+3

Questa risposta è corretta, ma a seconda nel contesto in cui hai bisogno di questa lezione, potrebbe non essere quello che vuoi. Se '' 'T'' è una classe, questa implementazione restituirà '' null'', e se è una classe F #, il compilatore non ti permetterà (facilmente) di confrontarlo con '' null''. Quindi stai attento. –

+0

@OverlordZurg Grazie per avermelo fatto notare. Ho aggiunto un TL; DR; :-) – CaringDev

+1

Il codice in [questa risposta] (http: // stackoverflow.it/a/10746877/636019) esegue controlli null per qualsiasi tipo di riferimento, F # o altrimenti. – ildjarn