F# implemented abstract static member causes Bad image format invoked through reflection
See original GitHub issueRepro steps
In order to reproduce the issue I create an implementation of IParsable from F#, then invoke it through reflection
open System
open System.ComponentModel
// from https://madskristensen.net/post/A-shorter-and-URL-friendly-GUID
let toStr (x : Guid) =
let enc = Convert.ToBase64String(x.ToByteArray())
let enc = enc.Replace("/", "_").Replace("+", "-")
enc.Substring(0, 22)
let fromStr (encoded : string) =
let encoded = encoded.Replace("_", "/").Replace("-", "+")
let buffer = Convert.FromBase64String(encoded + "==")
if buffer.Length = 16 then Some(Guid buffer)
else None
let tryParseId (prefix : string) (str : string) =
if str.StartsWith(prefix) then fromStr (str.Substring prefix.Length)
else None
let parseId prefix str =
let maybeParsed = tryParseId prefix str
match maybeParsed with
| Some g -> g
| None -> raise (FormatException str)
type CustomerId =
{ Value : Guid }
static member Default : CustomerId = { Value=Guid.Empty }
static member Parse(str : string) : CustomerId = { Value = parseId "c-" str }
override this.ToString() = sprintf "c-%s" (toStr this.Value)
interface IParsable<CustomerId> with
static member Parse(s:string, f:IFormatProvider) = CustomerId.Parse(s)
static member TryParse(s:string, f:IFormatProvider, result:byref<CustomerId>) =
try
result <- CustomerId.Parse(s)
true
with _ ->
result <- Unchecked.defaultof<_>
false
typeof<CustomerId>.GetInterface("IParsable`1").GetMethod("Parse").Invoke(null, [| "c-ReJ_cYj8l0WmonC0k0hQvw"; null |]);;
(**
System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation.
---> System.BadImageFormatException: Bad IL format.
at InvokeStub_IParsable`1.Parse(Object, Object, IntPtr*)
at System.Reflection.MethodInvoker.Invoke(Object obj, IntPtr* args, BindingFlags invokeAttr)
--- End of inner exception stack trace ---
at System.Reflection.MethodInvoker.Invoke(Object obj, IntPtr* args, BindingFlags invokeAttr)
at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
at <StartupCode$FSI_0030>.$FSI_0030.main@() in /Users/mathieu/src/cs/Saithe/stdin:line 158
at System.RuntimeMethodHandle.InvokeMethod(Object target, Void** arguments, Signature sig, Boolean isConstructor)
at System.Reflection.MethodInvoker.Invoke(Object obj, IntPtr* args, BindingFlags invokeAttr)
Stopped due to error
*)
Expected behavior
If you implement the same logic but with an instance interface then you get the expected behaviour:
type IParsableInst<'T> = interface
abstract member Parse : string -> 'T
abstract member TryParse : string*byref<'T> -> bool
end
type CustomerId2 =
{ Value2 : Guid }
static member Default : CustomerId2 = { Value2=Guid.Empty }
static member Parse(str : string) : CustomerId2 = { Value2 = parseId "c-" str }
override this.ToString() = sprintf "c-%s" (toStr this.Value2)
interface IParsableInst<CustomerId2> with
member this.Parse(s:string) = CustomerId2.Parse(s)
member this.TryParse(s:string, result:byref<CustomerId2>) =
try
result <- CustomerId2.Parse(s)
true
with _ ->
result <- Unchecked.defaultof<_>
false
typeof<CustomerId2>.GetInterface("IParsableInst`1").GetMethod("Parse").Invoke(CustomerId2.Default, [| "c-ReJ_cYj8l0WmonC0k0hQvw" |]);;
// val it: obj = { Value2 = 717fe245-fc88-4597-a6a2-70b4934850bf }
Actual behavior
Throws System.BadImageFormatException
Known workarounds
It’s a new feature in .net.
Related information
- Operating system (Windows Appveyor Visual Studio 2022 image, Mac OS X, GitHub Ubuntu latest (at the time of writing 2022-11) )
- .NET Runtime kind (.NET 7.0.100)
Issue Analytics
- State:
- Created 10 months ago
- Comments:18 (18 by maintainers)
Top Results From Across the Web
BadImageFormatException when invoking static abstract ...
The expected behaviour would be to match the behaviour of regular instance methods on interfaces (you can invoke them through reflection).
Read more >C# Template Function: Accessing static abstract members ...
C# Template Function: Accessing static abstract members throws System. BadImageFormatException - Stack Overflow.
Read more >Can we declare the static variables and methods in an ...
Yes, an abstract class can have static variables and static methods: ... Deeksha and Bharti both stated that static class members are shareable...
Read more >Static abstract members in interfaces - .NET
Learn about the .NET 6 breaking change where `static` interface members can now be marked `abstract`.
Read more >Static Keyword - Manual
Static properties are accessed using the Scope Resolution Operator ( :: ) and cannot be accessed through the object operator ( -> )....
Read more >Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start FreeTop Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
Top GitHub Comments
Unless they have the same issue?
Thanks! I’ll report it to the runtime repo!