When I look the definition of event class in f#
type Event<'T> =
class
new Event : unit -> Event<'T>
member this.Trigger : 'T -> unit
member this.Publish : IEvent<'T>
end
I can pass only one type on event class like
let nameChanged = new Event<unit>()
But I saw some sample too, that pass two variables like
let propertyChanged = Event<PropertyChangedEventHandler, PropertyChangedEventArgs>()
How could be that be possible?
And when I implement an interface like
module SapHandler
open SAP.Middleware.Connector
type Connector() =
let configurationChanged = Event<RfcDestinationManager.ConfigurationChangeHandler, RfcConfigurationEventArgs>()
interface IDestinationConfiguration with
member self.ChangeEventsSupported() =
false
[<CLIEvent>]
member self.ConfigurationChanged = configurationChanged.Publish
The compiler complain:
The type 'RfcDestinationManager.ConfigurationChangeHandler' has a non-standard delegate type
Why?
The definition of delegate type is:
It's possible because there's another class too:
type Event<'Delegate,'Args (requires delegate)> =
class
new Event : unit -> Event<'Delegate,'Args>
member this.Trigger : obj * 'Args -> unit
member this.Publish : IEvent<'Delegate,'Args>
end
You're getting that error because your delegate for the event is probably missing the first object sender argument which is standard in .net. You can use Control.DelegateEvent<'Delegate> to get around this
let propertyChanged = DelegateEvent<RfcDestinationManager.ConfigurationChangeHandler>()
Related
Can I take this statement:
let propertyChanged =
Event<PropertyChangedEventHandler,PropertyChangedEventArgs>()
And rename it to:
let propertyChangedDelegate =
Event<PropertyChangedEventHandler,PropertyChangedEventArgs>()
I'm trying to understand the ceremony of event declaration within F#.
Specifically, I am trying to understand the difference between:
let propertyChanged =
Event<PropertyChangedEventHandler,PropertyChangedEventArgs>()
And:
interface INotifyPropertyChanged with
[<CLIEvent>]
member this.PropertyChanged = propertyChanged.Publish
Here's the entire scope of code here:
open System.ComponentModel
open Microsoft.FSharp.Quotations.Patterns
type ViewModelBase () =
let propertyChanged =
Event<PropertyChangedEventHandler,PropertyChangedEventArgs>()
let getPropertyName = function
| PropertyGet(_,pi,_) -> pi.Name
| _ -> invalidOp "Expecting property getter expression"
interface INotifyPropertyChanged with
[<CLIEvent>]
member this.PropertyChanged = propertyChanged.Publish
member private this.NotifyPropertyChanged propertyName =
propertyChanged.Trigger(this,PropertyChangedEventArgs(propertyName))
member this.NotifyPropertyChanged quotation =
quotation |> getPropertyName |> this.NotifyPropertyChanged
Can someone please explain to me how events are implemented in F#?
In F#, events are just values of type IEvent<T> that you can pass around. So, to create an event, you need to write some implementation of this interface (which handles adding and removing event handlers).
The Event<T> type provides a default sensible implementation of the interface. When you write:
let propertyChanged =
Event<PropertyChangedEventHandler,PropertyChangedEventArgs>()
You're just using a class from the F# library that creates a new implementation of an event which accepts PropertyChangedEventArgs and can be used with event handlers of the delegate type PropertyChangedEventHandler.
The returned propertyChanged object has two things:
Publish property gives you the IEvent<T> value (representing event)
Trigger method invokes the event (which then invokes all the event handlers that are registered with the IEvent<T> value that is hidden inside the propertyChanged object).
So writing:
interface INotifyPropertyChanged with
[<CLIEvent>]
member this.PropertyChanged = propertyChanged.Publish
Is just a way of exposing the event (using the CLIEvent attribute to tell the F# compiler that it should be compiled as a .NET compatible event).
There is a more detailed documentation on F# events on MSDN if you want to learn more.
I have written a class in F# implementing an interface in order to build a C#-friendly interface for my F#-assembly.
I have written some of the properties as indexed properties. However, when I try to use the type from C#, I only get the synthetic get_PropertyName methods in intellisense and the compiler likewise complains in case I want to use the indexed properties like I would do for C# ones.
Code for reference:
type IMyInterfaceType =
abstract MyProperty : MyType1 with get
abstract MyIndexedProperty : MyType2 -> MyType3 with get
abstract MyTwoDimensionalIndexedProperty : (MyType4 * MyType5) -> MyType6 with get
type MyInterfaceType =
new () = { }
interface IMyInterfaceType with
member this.MyProperty with get () = new MyType1 ()
member this.MyIndexedProperty with get parameter = new MyType3 ()
member this.MyTwoDimensionalIndexedProperty with get pair = new MyType6 ()
When trying to access this class from C#, I only get methods
get_MyIndexedProperty(MyType2 parameter)
get_MyTwoDimensionalIndexedProperty(Tuple<MyType4, MyType5>)
instead of the indexed properties I had hoped for.
Am I doing something wrong or is this a known issue?
cheers
--Mathias.
Response to the original question:
Indexer properties in C# have special name Item thus to create indexer accessible from C# you must name your indexer property "Item", e.g.:
type X () =
member this.Item with get key = ....
Now it can be accessed both in F# using (x : X).[key] or in C# using x[key] .
Response to the updated question:
C# does not support indexed properties the way F# does. Instead using additional type is advised: https://msdn.microsoft.com/en-us/library/aa288464%28v=vs.71%29.aspx
So you can try to use something like this:
[<AbstractClass>]
type Indexer<'index, 'result> () =
abstract Get : 'index -> 'result
member this.Item with get key = this.Get key
type IMyInterfaceType =
abstract MyProperty : MyType1 with get
// F# indexed propetties
abstract MyIndexedProperty : MyType2 -> MyType3 with get
// C# workaround
abstract MyCSharpIndexedProperty : Indexer<MyType2, MyType3> with get
type MyInterfaceType () as this =
let proxy =
{ new Indexer<MyType2, MyType3> () with
member __.Get key = (this :> IMyInterfaceType).MyIndexedProperty key }
interface IMyInterfaceType with
member __.MyProperty with get () = new MyType1 ()
member __.MyIndexedProperty with get key = new MyType3 ()
member __.MyCSharpIndexedProperty with get () = proxy
And two dimensional property similarly by creating Indexer<'index1, 'index2, 'result> () = ...
I have the following interface in C#
public interface IDog
{
String Bark();
}
I want to create an implementation in F#. I had no problem with this:
type GermanShepherd() =
interface IDog with
member this.Bark() = "Woof"
but when I added a supporting function that is not part of the interface like this:
type GermanShepherd() =
interface IDog with
member this.Bark() = "Woof"
member this.Eat() = "Yummy"
the compiler complained:
Error 1 No abstract or interface member was found that corresponds to this override
Error 2 This value is not a function and cannot be applied*
Is there a way of implementing private/internal functions with a type that implements an interface without those functions being part of the interface? I can't change the interface in my 'real' application b/c there are other projects that implement the interface. None of the examples on MSDN that I found have this particular scenario.
The interface block should only contain functions that are part of the interface, but you can place other functions before the block:
type GermanShepherd() =
member this.Eat() = "Yummy"
interface IDog with
member this.Bark() = "Woof"
If you do not need a public member, then you can go with a private let-bound function:
type GermanShepherd() =
let eat() = "Yummy"
interface IDog with
member this.Bark() = "Woof"
Also note that F# currently only allows explicit interface implementations, which means that you can treat GermanShepherd as IDog, but you won't see IDog members explicitly:
let g = GermanShepherd()
g.Eat() // OK
g.Bark() // Error, interface members are implemented explicitly
let d = g :> IDog // To 'Bark', we need to get 'IDog' first
d.Bark() // OK
One workaround for this is to add the Bark method explicitly as a separate member outside of the interface block. Although there is F# language issue for this too!
I have the below code:
type IQuery =
abstract List<'T> : unit -> IList<'T>
let create (str)=
let getList () : IList<'T> = upcast List<'T>()
{ new IQuery with
member this.List<'T>() = getList<'T>()
And for the last line it gives me a warning stating that:
The method or function 'getList' should not be given explicit type argument(s) because it does not declare its type parameters explicitly
However if I remove <'T> from getList call then I get a compilation error as :
The member 'List<'T> : unit -> IList<'a>' does not have the correct type to override the corresponding abstract method. The required signature is 'List<'T> : unit -> IList<'T>'.
What can I do ?
You can declare getList with an explicit type parameter:
let getList<'T> () : IList<'T> = upcast List<'T>()
You then get an error:
Explicit type parameters may only be used on module or member bindings
If you then move the let binding to the top-level at the same scope as the type, it all works:
type IQuery =
abstract List<'T> : unit -> IList<'T>
let getList<'T> () : IList<'T> = upcast List<'T>()
let create (str) =
{ new IQuery with
member this.List<'T>() = getList<'T>()
}
If your real code has getList using values only in scope in create, like str, you'll need to add them as explicit parameters to getList.
I have an type that is implementing IEnumerable<T> interface, all is ok:
open System
type Bar() =
interface Collections.IEnumerable with
member x.GetEnumerator () = null
interface Collections.Generic.IEnumerable<int> with
member x.GetEnumerator () = null
But things goes wrong if type inherits IEnumerable interface implementation via the base type:
open System
type Foo() =
interface Collections.IEnumerable with
member x.GetEnumerator () = null
type Bar() =
inherit Foo()
interface Collections.Generic.IEnumerable<int> with
member x.GetEnumerator () = null
Code above produces the type inference errors:
The member 'GetEnumerator<'a0 when 'a0 : null> : unit -> 'a0 when 'a0 : null' does not have the correct type to override any given virtual method
The member 'GetEnumerator<'a0 when 'a0 : null> : unit -> 'a0 when 'a0 : null' does not have the correct number of method type parameters. The required signature is 'GetEnumerator : unit -> Collections.Generic.IEnumerator<int>'.
Am I doing something wrong or this is an F# compiler bug?
Microsoft (R) F# 2.0 Interactive build 4.0.30319.1
Update more canonical example:
type IFoo = abstract Bar : obj list
type IFoo<'a> = abstract Bar : 'a list
inherit IFoo
/* ok */
type Foo = interface IFoo with member x.Bar = []
interface IFoo<Foo> with member x.Bar = []
/* fail */
type FooBase = interface IFoo with member x.Bar = []
type FooDerived = interface IFoo<Foo> with member x.Bar = [] // <---
inherit FooBase
/*
error FS0017: The member 'get_Bar : unit -> 'a list' does not
have the correct type to override any given virtual method.
*/
The compiler cannot infer the correct type from your "null"-implementation. Try
open System
type Foo() =
interface Collections.IEnumerable with
member x.GetEnumerator () = null
type Bar() =
inherit Foo()
interface Collections.Generic.IEnumerable<int> with
member x.GetEnumerator () : Collections.Generic.IEnumerator<int> = null
UPDATE:
The reason is, that the type of the GetEnumerator method implemented by the Bar type is ambigous as IEnumerable<'a> implements/inherits the non-generic IEnumerable which also specifies a (non-generic) GetEnumerator method. So, how should the compiler infer, which method exactly you are trying to implement if all he gets is null? Therefore we need a type annotation in this case.
This is not a bug, this is just an type inference fail because of F# may implement inherited interface members in the derived interface implementation declaration:
type IA = abstract A : int
type IB = inherit IA
type IC = inherit IB
type Baz =
interface IC with
member x.A = 1
So in my example I should specify the correct return type explicitly because member x.GetEnumerator() in derived Bar type may match both IEnumerable.GetEnumerator() and IEnumerable<T>.GetEnumerator().