I need to convert the following C# code to F#. How to convert new object[] {} in the following code?
var table = (Hashtable) cookies.GetType().InvokeMember("m_domainTable",
BindingFlags.NonPublic |
BindingFlags.GetField |
BindingFlags.Instance,
null,
cookies,
new object[] { });
Use [||] if type inference doesn't infer it properly you can always annotate the type:
... ,null ,cookies, [||] : obj [])
But in that specific case the type annotation will not be needed since there are no conflicting overloads:
let table =
cookies.GetType()
.InvokeMember("m_domainTable",
BindingFlags.NonPublic |||
BindingFlags.GetField |||
BindingFlags.Instance,
null,
cookies,
[||]) :?> Hashtable
Related
Getting into the bowels now. Hopefully this is the last time I have to deal with Reflection for a while and I can return to the high level where I belong.
I have a type "PrimaryKey" defined as such.
type PrimaryKey<'x> =
| Id of int
| EmptyPrimaryKey
Then a bunch of record types associated with database tables, for example:
type User = {
user_id: PrimaryKey<User>
username: string
email: string
address_id: PrimaryKey<Address>
} with
static member DatabaseTable = "users"
I have written a custom type handler for Dapper to handle the Primary Key type.
type PrimaryKeyHandler<'X>() =
inherit SqlMapper.TypeHandler<PrimaryKey<'X>>()
(* I don't think this works but that's a future problem *)
override _.SetValue(param, value) =
let valueOrNull =
match value with
| PrimaryKey.Id id -> box id
| EmptyPrimaryKey -> null
param.Value <- valueOrNull
override _.Parse value =
if isNull value || value = box DBNull.Value
then EmptyPrimaryKey
else Id (value :?> int)
Now the problem with that is I have to call::
SqlMapper.AddTypeHandler (PrimaryKeyHandler<User>())
SqlMapper.AddTypeHandler (PrimaryKeyHandler<OtherRecordType>())
On every record that has a primary key. I'm basing my solution off of this: Dapper generic typehandler for F# Union types
But I don't understand it enough to adapt it to my needs, I think I need extra handling for the generic type.
What I've started with is this:
let RegisterTypeHandlers () =
let assembly = Assembly.GetCallingAssembly()
let handler = typedefof<PrimaryKeyHandler<_>>
assembly.GetTypes()
|> Seq.filter(fun t ->
FSharpType.IsRecord(t) && t.GetProperty("DatabaseTable") <> null
)
Which successfully returns a list of record types which have database table associations.
However trying to iterate over that list and call AddTypeHandler on all of those types fails:
let RegisterTypeHandlers () =
let assembly = Assembly.GetCallingAssembly()
let handler = typedefof<PrimaryKeyHandler<_>>
assembly.GetTypes()
|> Seq.filter(fun t ->
FSharpType.IsRecord(t) && t.GetProperty("DatabaseTable") <> null
)
|> Seq.iter(fun t ->
printfn $"Type: {t.Name}"
let ctor = handler
.MakeGenericType(t)
.GetConstructor(Array.empty)
.Invoke(Array.empty)
(typeof<SqlMapper>.GetMethods()
|> Seq.filter(fun methodInfo ->
if methodInfo.Name = "AddTypeHandler" && methodInfo.IsGenericMethodDefinition then
let gp = methodInfo.GetParameters()
not <| isNull gp && gp.Length = 1 && gp.[0].ParameterType.Name.Contains("TypeHandler")
else false)
|> Seq.head)
.MakeGenericMethod(t)
.Invoke(null, [| ctor |]) |> ignore
)
The error being
Unhandled exception. System.ArgumentException: Object of type 'MyModule.Common+PrimaryKeyHandler`1[Program+User]' cannot be converted to type 'Dapper.SqlMapper+TypeHandler`1[Program+User]'.
I've been looking at some of the GenericType functions in reflection but not really sure where to go from here.
First of all, you are getting an error saying that PrimaryKeyHandler<User> cannot be converted to type TypeHandler<User>. This is correct, because your type PrimaryKeyHandler<User> inherits from TypeHandler<PrimaryKey<User>>.
I think this happens because you get the AddTypeHandler method via reflection and then use MakeGenericMethod(t) to make it generic - but if t is User, then you get the wrong generic instantiation - you need to wrap t with PrimaryKey<..> around it first.
I have not tested this, but I think the following should work:
let addTyMi =
typeof<SqlMapper>.GetMethods()
|> Seq.find(fun methodInfo ->
if methodInfo.Name = "AddTypeHandler" &&
methodInfo.IsGenericMethodDefinition then
let gp = methodInfo.GetParameters()
not <| isNull gp && gp.Length = 1 &&
gp.[0].ParameterType.Name.Contains("TypeHandler")
else false)
let pkt = typedefof<PrimaryKey<_>>.MakeGenericType(t)
addTyMi.MakeGenericMethod(pkt).Invoke(null, [| ctor |]) |> ignore
It seems to me that there is also a non-generic overload of AddTypeHandler taking System.Type (by browsing GitHub source - I have not tried this). Maybe you could do just:
let pkt = typedefof<PrimaryKey<_>>.MakeGenericType(t)
SqlMapper.AddTypeHandler(pkt, ctor)
...avoiding some of the reflection. Also, ctor is a bad name, because the variable refers to the instance!
I am trying to get MailMessage in .NET to return a string of the MIME message, but this is not provided in the delivered class. There's another excellent answer on how to create a C# extension method to monkey patch the class to provide the functionality. I am trying to port that to F# with a type extension, but I am getting hung up on how to provide the parameters (especially given that one of them is an F# keyword).
Would really appreciate an explanation of how this is done properly with the answer.
Here's what I have gotten so far (this will, of course, not currently compile):
open System.Net.Mail
module MailExtension =
type MailMessage with
member this.toEml mail =
let stream = new MemoryStream();
let mailWriterType = mail.GetType().Assembly.GetType("System.Net.Mail.MailWriter");
let mailWriter = Activator.CreateInstance(
type: mailWriterType,
bindingAttr: BindingFlags.Instance | BindingFlags.NonPublic,
binder: null,
args: new object[] { stream },
culture: null,
activationAttributes: null)
mail.GetType().InvokeMember(
name: "Send",
invokeAttr: BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.InvokeMethod,
binder: null,
target: mail,
args: new object[] { mailWriter, true, true });
Encoding.UTF8.GetString(stream.ToArray());
Here is a few hints on how to translate C# to F#:
the ; is not longer required
use "use" instead of "let" for IDisposables
for arrays use [| member1, member2 |]
for named parameters use name=value
wrap keywords in names in ``name``
bitwise operators are ||| and &&&
use instance name instead of argument
Code that compiles:
open System
open System.IO
open System.Net.Mail
open System.Reflection
open System.Text
module MailExtension =
type MailMessage with
member this.toEml () =
use stream = new MemoryStream()
let mailWriterType = this.GetType().Assembly.GetType("System.Net.Mail.MailWriter")
let mailWriter = Activator.CreateInstance(
``type`` = mailWriterType,
bindingAttr = (BindingFlags.Instance ||| BindingFlags.NonPublic),
binder = null,
args = [| stream |],
culture = null,
activationAttributes = null)
this.GetType().InvokeMember(
name = "Send",
invokeAttr = (BindingFlags.Instance ||| BindingFlags.NonPublic ||| BindingFlags.InvokeMethod),
binder = null,
target = this,
args = [| mailWriter, true, true |])
Encoding.UTF8.GetString(stream.ToArray())
Then use:
open MailExtension
let m = new MailMessage()
m.toEml () |> ignore
I'm a newbie F# programmer, and I'm having some trouble getting the syntax for my F# program correct.
Essentially, I want to turn this C# code into F#:
class MyRiskyObject : BaseObject
{
private string field;
public MyRiskyObject(object foo, string data)
: base(foo)
{
try
{
this.data = RiskyOperation(data);
}
catch (ArgumentException)
{
DoSomethingElse();
}
}
}
I, so far, have something like
type MyRiskyObject
inherit BaseObject
val field : string
new (foo:object, data:string) = {
inherit BaseObject(foo)
try
field = RiskyOperation()
????????
}
I just can't get the syntax right...
Edit:
here is the actual code I'm working on:
type RegExpObject =
inherit CommonObject
val RegExp : Regex
val Global : bool
member x.IgnoreCase:bool =
(x.RegExp.Options &&& RegexOptions.IgnoreCase) = RegexOptions.IgnoreCase
member x.MultiLine:bool =
(x.RegExp.Options &&& RegexOptions.Multiline) = RegexOptions.Multiline
new (env, pattern, options, global') =
{
inherit CommonObject(env, env.Maps.RegExp, env.Prototypes.RegExp)
// Here, I need to catch the exception, and instead call RaiseSyntaxError.
RegExp = new Regex(pattern, options ||| RegexOptions.ECMAScript ||| RegexOptions.Compiled)
Global = global'
}
then RegExp = new Regex(pattern, options ||| RegexOptions.ECMAScript ||| RegexOptions.Compiled)
new (env, pattern) =
RegExpObject(env, pattern, RegexOptions.None, false)
Why not just delegate the real work to a separate free function, so the work doesn't have to be done directly in your class' constructor?
let createRegex pattern options =
try
Regex(pattern, options ||| RegexOptions.ECMAScript ||| RegexOptions.Compiled)
with
| :? System.ArgumentException -> RaiseSynaxError ()
Then your class (as demonstrated in your edit) would be:
type RegExpObject(env, pattern, options, global') //'
inherit CommonObject(env, env.Maps.RegExp, env.Prototypes.RegExp)
let RegExp = createRegex pattern options
let Global = global' //'
member x.IgnoreCase =
(x.RegExp.Options &&& RegexOptions.IgnoreCase) = RegexOptions.IgnoreCase
member x.MultiLine =
(x.RegExp.Options &&& RegexOptions.Multiline) = RegexOptions.Multiline
new (env, pattern) = RegExpObject(env, pattern, RegexOptions.None, false)
An advantage here is that, as #Brian indicated, no use of val would be necessary, making the class definition much cleaner.
Try the following
type MyRiskyObject(foo : obj, data : string) as this =
inherit BaseObject(foo)
let mutable data = data;
do
try
data <- this.RiskyOperation data
with
| :? System.ArgumentException -> this.DoSomethingElse()
Alternate example with non-mutable let binding where RiskOperation and DoSomethingElse are not members of MyRiskObject
type MyRiskyObject(foo : obj, data : string) =
inherit BaseObject(foo)
let data =
try
OtherModule.RiskyOperation data
with
| :? System.ArgumentException ->
OtherModule.DoSomethingElse()
data
I've been working on polishing up my JSON code for my ECMAScript runtime and I decided to run an experiment. The following str function has 4 logical steps which I've broken up into functions and marked them inline.
and private str (state:StringifyState) (key:string) (holder:IObject) : IDynamic =
let inline fourth (value:IDynamic) =
match value.TypeCode with
| LanguageTypeCode.Null ->
state.environment.CreateString "null" :> IDynamic
| LanguageTypeCode.Boolean ->
let v = value :?> IBoolean
state.environment.CreateString (if v.BaseValue then "true" else "false") :> IDynamic
| LanguageTypeCode.String ->
let v = value :?> IString
state.environment.CreateString (quote v.BaseValue) :> IDynamic
| LanguageTypeCode.Number ->
let v = value :?> INumber
if not (Double.IsInfinity(v.BaseValue))
then v.ConvertToString() :> IDynamic
else state.environment.CreateString "null" :> IDynamic
| LanguageTypeCode.Object ->
let v = value :?> IObject
let v = if v.Class = "Array" then ja state v else jo state v
state.environment.CreateString v :> IDynamic
| _ ->
state.environment.Undefined :> IDynamic
let inline third (value:IDynamic) =
match value.TypeCode with
| LanguageTypeCode.Object ->
let v = value :?> IObject
match v.Class with
| "Number" ->
fourth (v.ConvertToNumber())
| "String" ->
fourth (v.ConvertToString())
| "Boolean" ->
fourth (v.ConvertToBoolean())
| _ ->
fourth value
| _ ->
fourth value
let inline second (value:IDynamic) =
match state.replacerFunction with
| :? ICallable as f ->
let args = state.environment.CreateArgs ([| state.environment.CreateString key :> IDynamic; value |])
let value = f.Call (state.environment, holder :> IDynamic, args)
third value
| _ ->
third value
let inline first (value:IDynamic) =
match value with
| :? IObject as v ->
let toJSON = v.Get "toJSON"
match toJSON with
| :? ICallable as f ->
let args = state.environment.CreateArgs ([| state.environment.CreateString key :> IDynamic |])
let value = f.Call (state.environment, value, args)
second value
| _ ->
second value
| _ ->
second value
first (holder.Get key)
I compiled with full optimizations and opened up the resulting assembly with Reflector to see the results.
[CompilationArgumentCounts(new int[] { 1, 1, 1 })]
internal static IDynamic str(StringifyState state, string key, IObject holder)
{
IObject obj3;
ICallable callable;
ICallable callable2;
IArgs args;
IDynamic dynamic3;
IDynamic dynamic4;
ICallable callable3;
IDynamic dynamic5;
IBoolean flag;
IString str;
INumber number;
IObject obj4;
string str2;
INumber number2;
IObject obj5;
string str3;
IString str4;
IBoolean flag2;
IDynamic thisBinding = holder.Get(key);
IObject obj2 = thisBinding as IObject;
if (obj2 == null)
{
callable = state.replacerFunction# as ICallable;
if (callable == null)
{
switch (thisBinding.TypeCode)
{
case LanguageTypeCode.Object:
obj3 = (IObject) thisBinding;
str2 = obj3.Class;
if (!string.Equals(str2, "Number"))
{
if (string.Equals(str2, "String"))
{
dynamic3 = obj3.ConvertToString();
switch (dynamic3.TypeCode)
{
case LanguageTypeCode.Null:
return (IDynamic) state.environment#.CreateString("null");
case LanguageTypeCode.Boolean:
flag = (IBoolean) dynamic3;
return (IDynamic) state.environment#.CreateString(!flag.BaseValue ? "false" : "true");
case LanguageTypeCode.String:
str4 = (IString) dynamic3;
return (IDynamic) state.environment#.CreateString(quote(str4.BaseValue));
case LanguageTypeCode.Number:
number = (INumber) dynamic3;
if (double.IsInfinity(number.BaseValue))
{
return (IDynamic) state.environment#.CreateString("null");
}
return (IDynamic) number.ConvertToString();
// ... I removed a large amount of code.
return (IDynamic) state.environment#.Undefined;
}
Clearly the inline modifier is quite literal. The code is quite huge and with some preliminary tests is very efficient. One might consider throwing inline on all of their functions if they didn't care about the size of the resulting assemblies. What are some guidelines I can follow to know when the use of inline is appropriate? If possible I would like to avoid having to measure performance every single time to determine this.
If you are using inline solely for performance considerations, then I think that all of the typical performance-related advice applies. Most importantly, set a performance target and profile your application for hotspots. Then use inline if you have reason to believe that it will improve performance, and test to verify that it does. Keep in mind that the IL that the F# compiler generates is JIT compiled anyway, so small functions (in terms of IL size) may be inlined in the compilation to machine code even if you don't use inline in your F# code.
I typically only use inline when I want to use statically resolved type variables (e.g. because of member constraints).
I agree with kvb's answer, but here are two specific reasons not to
consider throwing inline on all of their functions if they didn't care about the size of the resulting assemblies.
The obvious case is that inlining anonymous functions won't work.
More inlining (especially of big functions) -> less (effectively) code fits into cache -> the program works slower.
F# interactive is a powerful development tool as it allows to run either WinForm or Wpf window and invoke arbitrary code in there.
This gives a way for a 'try-before-you code' approach.
Very often I wish to 'break the boundaries' explicitly and
invoke private/protected methods
access/change private fields and properties
Is there a workaround to achieve this?
FSI doesn't provide any particular support for this, but you can use Reflection to do the things you want.
open System.Reflection
let field = typeof<MyType>.GetField("fieldName", BindingFlags.NonPublic ||| BindingFlags.Instance)
field.SetValue(myInstance, newVal)
You can go further and define methods or operators to make this even easier. For instance you can set up F#'s dynamic assignment operator to assign to private fields:
let (?<-) o s v =
let field = (o.GetType()).GetField(s, BindingFlags.NonPublic ||| BindingFlags.Instance)
field.SetValue(o,v)
myInstance?fieldName <- newVal (* Note: no quotes around fieldName here *)
Here's some crude code to resolve public or private fields, properties, or methods. Note that there are plenty of ways in which this will fail (in particular, trying to use it on overloaded methods will not work).
open System
open System.Reflection
open Microsoft.FSharp.Reflection
type DynamicHelper =
static member MkMethod<'t,'u> (mi:MethodInfo) o : 't -> 'u=
let typ = typeof<'t>
fun t ->
let args =
if (typ = typeof<unit>) then [||]
else
if not (FSharpType.IsTuple typ) then [| box t |]
else
FSharpValue.GetTupleFields t
mi.Invoke(o, args) :?> 'u
let (?) (o:'a) s : 'b =
let ty = o.GetType()
let field = ty.GetField(s, BindingFlags.Instance ||| BindingFlags.Public ||| BindingFlags.NonPublic)
if field <> null then field.GetValue(o) :?> 'b
else
let prop = ty.GetProperty(s, BindingFlags.Instance ||| BindingFlags.Public ||| BindingFlags.NonPublic)
if prop <> null then prop.GetValue(o, null) :?> 'b
else
let meth = ty.GetMethod(s, BindingFlags.Instance ||| BindingFlags.Public ||| BindingFlags.NonPublic)
let d,r = FSharpType.GetFunctionElements(typeof<'b>)
typeof<DynamicHelper>.GetMethod("MkMethod").MakeGenericMethod([|d;r|]).Invoke(null, [| box meth; box o |]) :?> 'b
With this you can dynamically invoke methods and properties as such:
let (t:System.Type) = "test"?GetType()?BaseType