I'm trying to build an Attribute that validates a certain instance of a type.
In order to do this I have to cast the ObjectInstance
to that type.
And I need to set the attribute on the member of that type.
So we need to resort to the and
keyword for the circular definition.
However in the following case I get the error that
A custom attribute must invoke an object constructor
On the line marked below.
namespace Test
open System
open System.ComponentModel.DataAnnotations
[<AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)>]
type MyAttribute() =
class
inherit ValidationAttribute ()
override this.IsValid (value: Object, validationContext: ValidationContext) =
match validationContext.ObjectInstance with
| :? MyClass as item ->
// TODO more validation
ValidationResult.Success
| _ ->
new ValidationResult("No no no")
end
and MyClass(someValue) =
[<Required>]
[<Range(1, 7)>]
//vvvvvvvvvvvvvvv
[<MyAttribute>]
//^^^^^^^^^^^^^^^
member this.SomeValue : int = someValue
I tried manually invoking the constructor, such as:
[<MyAttribute()>]
// or
[<new MyAttribute()>]
But none of them are accepted by the system.
Can an F# guru help me out here?
One solution would be to first describe your types in a signature files.
Since the attribute is specified in the signature file, you don't need to add it again in the implementation file:
Foo.fsi:
namespace Foo
open System
[<AttributeUsage(AttributeTargets.Property)>]
type MyAttribute =
inherit System.Attribute
new : unit -> MyAttribute
member Foo : unit -> MyClass
and MyClass =
new : someValue : int -> MyClass
[<MyAttribute()>]
member SomeValue : int
Foo.fs:
namespace Foo
open System
[<AttributeUsage(AttributeTargets.Property)>]
type MyAttribute() =
inherit Attribute()
member this.Foo () =
new MyClass(1)
and MyClass(someValue) =
// [<MyAttribute()>] -> specified in the fsi, still appears in compiled code
member this.SomeValue : int = someValue
See https://msdn.microsoft.com/en-us/library/dd233196.aspx for reference