2012-08-24 6 views
6

F # 3.0 aggiunge controlli più rigidi per le chiamate ai membri base e protected. Ho qualcosa come la seguente classe astratta in C# che ha metodi di supporto protected static da utilizzare per le classi derivate.Informazioni sulla modifica dell'utilizzo dei membri protetti/di base in F # 3.0

public abstract class Processor { 
    public abstract void Process(); 
    protected static void Helper(object arg) { } 
} 

in F #, uno di quei metodi di supporto è passato come una funzione di prima classe:

type DerivedProcessor() = 
    inherit Processor() 

    let init f = 
    f() 

    override x.Process() = 
    init Processor.Helper 

compila senza lamentarsi in 2.0, ma in 3,0 produce un errore:

A protected member is called or 'base' is being used. This is only allowed in the direct implementation of members since they could escape their object scope.

OK, è abbastanza facile da rispettare, basta avvolgere la chiamata in un altro membro statico

static member private HelperWrapper(arg) = Processor.Helper(arg) 

e passare quello intead. Ma perché?

C# non ha alcun problema con questo stesso modello.

public class HappyToCompile : Processor { 
    private void Init(Action<object> f) { 
     f(null); 
    } 

    public override void Process() { 
     Init(Helper); 
    } 
} 

Le domande:

  1. Perché sono stati aggiunti i controlli più severi?
  2. (e relativo) Quale terribile problema risolve una soluzione così banale?
  3. C'è un design migliore che questo dovrebbe incoraggiare?

risposta

5

Utilizzando le mie capacità di progettazione del linguaggio psichico, suppongo che F # 2.0 stia generando codice non verificabile. Vedi il messaggio this sul blog di Eric Lippert per una spiegazione di un problema correlato in C# (che è stato corretto dal C# 4, IIRC).

In breve, quando si crea una funzione F # si sta veramente creando una nuova classe derivante da FSharpFunc<_,_> e chiamando il proprio metodo protetto dall'interno di quella classe non è valida poiché non è nella catena di ereditarietà.

Ovviamente, piuttosto che disabilitare queste chiamate, il compilatore potrebbe semplicemente fare ciò che si sta facendo (creare un metodo privato e usarlo), ma forse si pensava che i benefici non fossero superiori ai costi di implementazione di quel miglioramento.

+0

Hai risposto alla prima domanda e il blog di Eric risponde alla seconda. È facile sorvolare le differenze tra 'Func <_>' e 'FSharpFunc <_>'. In che modo è stato possibile refactoring per eliminare 'protected'? – Daniel

+1

Bene, perché è protetto in primo luogo? Se vuoi che sia accessibile solo alle sottoclassi, allora non c'è molto che tu possa fare. Forse potresti esporre 'Helper' come una proprietà protetta di tipo 'Action ' piuttosto che come metodo, se ti aspetti che venga passato in giro come delegato comunque. – kvb

+3

Questa sarebbe una buona aggiunta a [_Breaking Changes_] (http://msdn.microsoft.com/en-us/library/hh416791). Un'altra [domanda recente] (http://stackoverflow.com/q/11978234/162396) potrebbe essere un buon candidato. – Daniel