Reflection F#:如何调用表达式。使用大小写类型在泛型类型中调用具有区分并集的方法?

Reflection F#:如何调用表达式。使用大小写类型在泛型类型中调用具有区分并集的方法?,reflection,.net-core,f#,Reflection,.net Core,F#,比方说,我有一个有区别的联合类型AccountEvent和一个类Aggregate,其中包含两种方法: Apply1(事件:AccountEvent) Apply2(事件:事件) 事件(事件:'TEvent)= 成员val Event=带有get的事件 类型聚合()= 成员this.Apply1(事件:AccountEvent)= () 成员this.Apply2(事件:event)= () 让createExpression(aggregateType:Type)(eventType:Ty

比方说,我有一个有区别的联合类型
AccountEvent
和一个类
Aggregate
,其中包含两种方法:

  • Apply1(事件:AccountEvent)
  • Apply2(事件:事件)
事件(事件:'TEvent)=
成员val Event=带有get的事件
类型聚合()=
成员this.Apply1(事件:AccountEvent)=
()
成员this.Apply2(事件:event)=
()
让createExpression(aggregateType:Type)(eventType:Type)(方法:MethodInfo)=
让instance=Expression.Parameter(aggregateType,“a”)
让eventParameter=Expression.Parameter(eventType,“e”)
let body=Expression.Call(实例、方法、eventParameter)
()
[]
让主argv=
让accountCreated=AccountEvent.accountCreated({
所有者=“Khalid Abuhakmeh”
AccountId=Guid.NewGuid()
起动平衡=1000米
CreatedAt=DateTimeOffset.UtcNow
})
让accountCreatedType=accountCreated.GetType()
让method1=typeof.GetMethods().Single(fun x->x.Name=“Apply1”)
createExpression类型类型类型方法1
createExpression类型accountCreatedType方法1
让method2=typeof.GetMethods().Single(fun x->x.Name=“Apply2”)
让eventAccountCreatedType=typedefof.MakeGenericType(accountCreatedType)
createExpression类型类型类型方法2
createExpression类型的eventAccountCreatedType方法2
0
在我当前的解决方案中,无法为
Apply2
生成表达式:

System.ArgumentException: Expression of type 'Program+Event`1[Program+AccountEvent+AccountCreated]' cannot be used for parameter of type 'Program+Event`1[Program+AccountEvent]' of method 'Void Apply2(Event`1)'
Parameter name: arg0
  at at System.Dynamic.Utils.ExpressionUtils.ValidateOneArgument(MethodBase method, ExpressionType nodeKind, Expression arguments, ParameterInfo pi, String methodParamName, String argumentParamName, Int32 index)
  at at System.Linq.Expressions.Expression.Call(Expression instance, MethodInfo method, Expression arg0)
  at at System.Linq.Expressions.Expression.Call(Expression instance, MethodInfo method, IEnumerable`1 arguments)
  at at System.Linq.Expressions.Expression.Call(Expression instance, MethodInfo method, Expression[] arguments)
  at Program.doingStuff(Type aggregateType, Type eventType, MethodInfo method) in C:\Users\eperret\Desktop\ConsoleApp1\ConsoleApp1\Program.fs:40
  at Program.main(String[] argv) in C:\Users\eperret\Desktop\ConsoleApp1\ConsoleApp1\Program.fs:61
我想知道如何调整表达式的创建以接受
事件


我在想,也许需要一个中间层来拥有一个从
AccountEvent.AccountCreated
到其基类
AccountEvent
(这就是如何编译有区别的联合)的转换层,或者更准确地说,考虑到泛型,从
Event很难说这是否回答了您的问题

open System
open System
type AccountCreation = {
    Owner: string
    AccountId: Guid
    CreatedAt: DateTimeOffset
    StartingBalance: decimal
}

type Transaction = {
    To: Guid
    From: Guid
    Description: string
    Time: DateTimeOffset
    Amount: decimal
}

type AccountEvent =
    | AccountCreated of AccountCreation
    | AccountCredited of Transaction
    | AccountDebited of Transaction
type CheckinEvent =
    | CheckedIn
    | CheckedOut
type Event<'T> = AccountEvent of AccountEvent | OtherEvent of 'T
let ev : Event<CheckinEvent> = AccountEvent (AccountCreated {
      Owner= "string"
      AccountId= Guid.NewGuid()
      CreatedAt=  DateTimeOffset()
      StartingBalance=0m
    })
let ev2 : Event<CheckinEvent> = OtherEvent CheckedOut
let f ev =
  match ev with
      | AccountEvent e -> Some e
      | OtherEvent (CheckedOut) -> None 
      | OtherEvent (CheckedIn) -> None 

let x = f ev
let y = f ev2
开放系统
开放系统
类型AccountCreation={
所有者:字符串
帐户ID:Guid
CreatedAt:DateTimeOffset
起始余额:十进制
}
交易类型={
收件人:Guid
发件人:Guid
描述:字符串
时间:DateTimeOffset
金额:十进制
}
类型AccountEvent=
|AccountCreation的AccountCreated
|交易账户
|记入交易借方的账户
类型检查事件=
|检查
|检查出
键入事件类型e
|其他事件(CheckedOut)->无
|其他事件(选中)->无
设x=f-ev
设y=f ev2

之后,像这样的匹配语句可能会简化所有这些。老实说,对我来说,准确地理解您在那里做的事情有点复杂,但是使用函数而不是方法以及使用匹配语句似乎可以实现相同的目标。理想情况下,您可能应该在DU中完全拼写出类型,而不是使用泛型,这样您将得到编译时检查,而不是运行时错误,并且可以确定编译器完全覆盖了您的代码

我已经改写了我的问题。主要是关于
表达式
的生成,以及允许
GenericType
用于
GenericType
。你可能对
GenericType
感兴趣,但是我必须警告你,你越是迷失在黑暗中,你就越是孤独。你在说什么黑暗?对不起,这么富有诗意。您正在远离编译时检查,远离常见的操作方式。很可能存在一种在不丢失编译时检查的情况下实现目标的方法。在F#中,我们经常尝试尽可能多地使用编译器,因为它可以减少bug。我们甚至不知道这些:x,需要检查一下。