2012-08-24 6 views
6

F # 3.0 dodaje ostrzejsze kontrole w odniesieniu do wywołań base i protected członków. Mam coś podobnego do następującej klasy abstrakcyjnej w języku C#, która ma pomocnicze metody protected static używane przez klasy pochodne.Zrozumienie zmianę chronionego użytkowania użytkownik/bazy w F # 3,0

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

w F #, jedna z tych metod pomocniczych jest przekazywana jako funkcja pierwszej klasy:

type DerivedProcessor() = 
    inherit Processor() 

    let init f = 
    f() 

    override x.Process() = 
    init Processor.Helper 

kompiluje bez zarzutu w 2,0, ale 3,0 generuje błąd:

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, jest to dość łatwe do spełnienia, wystarczy zawinąć rozmowę w innym statycznym członku.

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

i przekazać tę inte. Ale dlaczego?

C# nie ma problemu z tym samym wzorem.

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

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

pytania:

  1. Dlaczego surowsze kontrole dodana?
  2. (i pokrewne) Co robi straszny problem, takie trywialne adres obejście?
  3. Czy istnieje lepszy design, który to ma zachęcić?

Odpowiedz

5

Korzystając z moich umiejętności w zakresie projektowania języków psychicznych, zgaduję, że F # 2.0 generuje kod, który nie może być zweryfikowany. Zobacz post na blogu Eric Lipperta na this dla wyjaśnienia pokrewnego problemu w C# (który został naprawiony od C# 4, IIRC).

Krótko mówiąc, po utworzeniu funkcji F # naprawdę tworzysz nową klasę pochodzącą od FSharpFunc<_,_>, a wywoływanie metody chronionej z poziomu tej klasy jest niepoprawne, ponieważ nie znajduje się w łańcuchu dziedziczenia.

Oczywiście, zamiast odrzucać te połączenia, kompilator może po prostu robić to, co robisz (tworzyć prywatną metodę i używać tego), ale być może uważa się, że korzyści nie przeważają nad kosztami wdrożenia tej poprawy.

+0

Odpowiedziałeś na pierwsze pytanie, a blog Eric odpowiada drugi. Łatwo prześwitują różnice między 'Func <_>' i 'FSharpFunc <_>'. Jak można to refaktoryzować, aby wyeliminować "chronione"? – Daniel

+1

Dlaczego jest on chroniony? Jeśli chcesz, aby był dostępny tylko dla podklas, wtedy nie ma zbyt wiele rzeczy, które możesz zrobić. Być może mógłbyś wystawić 'Helper' jako chronioną własność typu' Action 'zamiast jako metodę, jeśli spodziewasz się, że i tak zostanie przekazany jako delegat. – kvb

+3

Będzie to dobry dodatek do [_Breaking Changes_] (http://msdn.microsoft.com/en-us/library/hh416791). Kolejne [ostatnie pytanie] (http://stackoverflow.com/q/11978234/162396) może być również dobrym kandydatem. – Daniel