【问题标题】:MailMesage F# extension type to serialize to MIME stringMailMessage F# 扩展类型以序列化为 MIME 字符串
【发布时间】:2018-07-07 19:50:24
【问题描述】:

我试图在 .NET 中获取 MailMessage 以返回 MIME 消息的字符串,但这在交付的类中没有提供。还有另一个出色的 answer 介绍了如何创建 C# 扩展方法来猴子修补类以提供功能。我正在尝试使用类型扩展将其移植到 F#,但我对如何提供参数感到困惑(特别是考虑到其中一个参数是 F# 关键字)。

非常感谢您通过答案解释如何正确完成此操作。

这是我目前得到的(当然,目前还不能编译):

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());

【问题讨论】:

    标签: f# mailmessage rfc822


    【解决方案1】:

    这里有一些关于如何将 C# 转换为 F# 的提示:

    • ;不再需要
    • IDisposables 使用“use”而不是“let”
    • 对于数组使用 [|成员1,成员2 |]
    • 对于命名参数,使用 name=value
    • 在 ``name`` 中将关键字包装在名称中
    • 位运算符是|||和&&&
    • 使用实例名称而不是参数

    编译代码:

    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())
    

    然后使用:

    open MailExtension
    let m = new MailMessage()
    m.toEml () |> ignore
    

    【讨论】:

    • 这真的很有帮助。我现在应该能够在我的 MailMessage 对象上调用该 toEml 方法,但是在将代码加载到 fsi 之后,无论是作为对象方法还是(只是检查所有内容)作为 MailMessage 类上的静态方法,什么都没有出现。我在这里还缺少什么?
    • 更新:在使用前使用this代替mailopen MailExtension
    • 您在这里使用的是什么版本的 .NET Framework?所做的更改是绝对正确的,所以我可以调用实例方法,但我得到以下内容:System.MissingMethodException: Method 'System.Net.Mail.MailMessage.Send' not found. at System.RuntimeType.InvokeMember(String name, BindingFlags bindingFlags, Binder binder, Object target, Object[] providedArgs, ParameterModifier[] modifiers, CultureInfo culture, String[] namedParams) at FSI_0002.MailExtension.MailExtension.MailMessage.toEml(MailMessage X1) 看起来添加的参数绑定了错误的类。
    猜你喜欢
    • 2017-10-24
    • 2020-04-14
    • 2018-09-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-14
    • 1970-01-01
    相关资源
    最近更新 更多