2012-08-24 31 views
6

F # 3.0 agrega comprobaciones más estrictas para las llamadas a los miembros base y protected. Tengo algo así como la siguiente clase abstracta en C# que tiene protected static métodos auxiliares para ser utilizados por las clases derivadas.Comprender un cambio en el uso del miembro protegido/base en F # 3.0

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

En F #, uno de esos métodos de ayuda se pasa como una función de primera clase:

type DerivedProcessor() = 
    inherit Processor() 

    let init f = 
    f() 

    override x.Process() = 
    init Processor.Helper 

compila sin queja en 2.0, pero en 3,0 produce un error:

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, es bastante fácil de cumplir, simplemente envuelva la llamada en otro miembro estático

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

y pase ese intead. ¿Pero por qué?

C# no tiene ningún problema con este mismo patrón.

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

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

Las preguntas:

  1. Por qué se añadieron los controles más estrictos?
  2. (y relacionado) ¿Qué terrible problema hace una solución tan trivial?
  3. ¿Hay un mejor diseño que se supone que debe alentar?

Respuesta

5

Usando mis habilidades de diseño del lenguaje psíquico, supongo que F # 2.0 genera código no verificable. Ver this publicar en el blog de Eric Lippert para una explicación de un problema relacionado en C# (que se ha corregido desde C# 4, IIRC).

En resumen, cuando crea una función F #, realmente está creando una nueva clase derivada de FSharpFunc<_,_>, y llamar a su método protegido desde esa clase no es válido ya que no está en la cadena de herencia.

Por supuesto, en lugar de rechazar estas llamadas, el compilador podría hacer lo que está haciendo (crear un método privado y usarlo), pero tal vez se pensó que los beneficios no excedían el costo de implementar esa mejora.

+0

Respondió la primera pregunta, y el blog de Eric responde al segundo. Es fácil pasar por alto las diferencias entre 'Func <_>' y 'FSharpFunc <_>'. ¿Cómo podría ser refactorizado para eliminar 'protected'? – Daniel

+1

Bueno, ¿por qué está protegido en primer lugar? Si desea que sea accesible solo para subclases, entonces no hay mucho que pueda hacer. Quizás podría exponer 'Helper' como una propiedad protegida de tipo 'Acción ' en lugar de como un método, si espera que se pase como un delegado de todos modos. – kvb

+3

Esto sería una buena adición a [_Breaking Changes_] (http://msdn.microsoft.com/en-us/library/hh416791). Otra [pregunta reciente] (http://stackoverflow.com/q/11978234/162396) podría ser un buen candidato también. – Daniel

Cuestiones relacionadas