Where is the "undefined type"?

I define the following type extension:

type System.Reflection.MemberInfo with
    member x.GetAttribute<'T when 'T :> Attribute>(required, inherit') =
        match required, Attribute.GetCustomAttribute(x, typeof<'T>, inherit') with
        | true, null -> invalidOp (sprintf "Missing required attribute: %s" typeof<'T>.FullName)
        | _, attr -> attr :> 'T

      

The last match expression ( attr :> 'T

) gives an error:

Static coercion from an attribute to 'T includes an undefined type based on information up to that point in the program. Static coercion is not allowed on some types. Additional type annotations are required.

I tried annotating the return type of the function but got the same result. I would hate to change this to a dynamic cast. Is there a way to make it work static?

+2


a source to share


3 answers


It should be dynamic, right? You have an object that is of a static type System.Attribute

and you want to cast it to an actual concrete type.



open System
type System.Reflection.MemberInfo with 
  member x.GetAttribute<'T when 'T :> Attribute>(required, inherit') =  // '
    match required, Attribute.GetCustomAttribute(x, typeof<'T>, inherit') with 
    | true, null -> invalidOp (
        sprintf "Missing required attribute: %s" typeof<'T>.FullName)  // '
    | _, attr -> attr :?> 'T 

      

+3


a source


To clarify the meaning of the error message - the compiler makes the difference between static casting :>

(which is always safe, like casting from Random

to Object

) and dynamic pushing :?>

(which can crash).

In your case, you need to use dynamic cast. This is what the compiler means:



  • It says that "static coercion from an attribute to 'T

    is associated with an undefined type." This means that it doesn't know (at compile time) what the actual type is being used instead of the generic parameter 'T

    .

  • As a result, the compiler cannot check if the conversion from Attribute

    to will always be performed 'T

    (which is required in the case of static coercion). If, for example, the compiler has determined that the type 'T

    will always be Object

    , then the use of static coercion will be valid.

+1


a source


Corrected code in case anyone needs it (Brian's code is right too ... I just prefer type annotation in signature):

type System.Reflection.MemberInfo with
    member x.GetAttribute<'T when 'T :> Attribute>(required, inherit') : 'T =
        match required, Attribute.GetCustomAttribute(x, typeof<'T>, inherit') with
        | true, null -> invalidOp (sprintf "Missing required attribute: %s" typeof<'T>.FullName)
        | _, attr -> downcast attr

      

0


a source







All Articles