在 ClearScript 中使用匿名类型时禁止显示不相关的成员

Suppress irrelevant members when using an anonymous type in ClearScript

提问人:ElektroStudios 提问时间:7/7/2023 最后编辑:ElektroStudios 更新时间:7/7/2023 访问量:51

问:

我正在围绕 java 脚本库实现 https://linkify.js.org/ .NET 包装器。对于这个任务,我使用的是Microsoft的ClearScript

我遇到的唯一问题是在实现在 linkifyHtml 函数的 options 对象参数中传递的 attributes 属性时。

该函数需要在 java 脚本代码中出现如下参数:

attributes: {
  title: "External Link",
  etc: "etc..."
}

所以,我的想法是定义这个属性,它返回一个匿名类型:Attributes

Public Class LinkifyFormatOptions 

    Public Property Attributes As Func(Of LinkifyLinkType, String, Object) =
        Function(linkType As LinkifyLinkType, href As String) As Object
            Select Case linkType
                Case LinkifyLinkType.Url
                    Return New With {.test_attribute = "This is a test attribute"}
                Case Else
                    Return Nothing
            End Select
        End Function
        
End Class

...稍后我将调整其返回值以构建选项对象:

Friend Function GetLinkifyOptions() As Object
    Dim options As New With {
        .attributes = Function(href As String, linkType As String) As Object
                          Select Case linkType
                              Case "url"
                                  Return Me.Attributes(LinkifyLinkType.Url, href)
                              Case "email"
                                  Return Me.Attributes(LinkifyLinkType.Email, href)
                              Case "hashtag"
                                  Return Me.Attributes(LinkifyLinkType.Hashtag, href)
                              Case "mention"
                                  Return Me.Attributes(LinkifyLinkType.Mention, href)
                              Case "ticket"
                                  Return Me.Attributes(LinkifyLinkType.Ticket, href)
                              Case Else
                                  Return Nothing
                          End Select
                      End Function,
    .className = etc...,
    .formatHref = etc...,
    .etc = etc...
    }
End Function

...最后在此处调用 java-script 的函数:linkifyHtml

Imports Microsoft.ClearScript
Imports Microsoft.ClearScript.V8

Public Shared Function Linkify(str As String,
                               [interface] As LinkifyInterface,
                               Optional plugins As LinkifyPlugins = LinkifyPlugins.None,
                               Optional formatOptions As LinkifyFormatOptions = Nothing) As String

    ' Argument validations and etc...

    Using engine As New V8ScriptEngine("linkify_engine", V8ScriptEngineFlags.DisableGlobalMembers)
        Dim options As Object = formatOptions.GetLinkifyOptions()
        ' linkify.js scripts loading and etc...
        
        Dim linkifyFunction As ScriptObject = DirectCast(engine.Evaluate("linkifyHtml"), ScriptObject)
        Return CStr(linkifyFunction.Invoke(asConstructor:=False, str, options))
    End Using
    
End Function

问题在于 ClearScript 引擎公开了该类型的成员,如“ToString”方法、“GetHashCode”等。Object

这是我调用 java-script 函数后得到的输出:linkifyHtml

<p>Domain: <a href="http://example.domain.com" $test_attribute="This is a test attribute" ToString="[object Object]" Equals="[object Object]" GetHashCode="[object Object]" GetType="[object Object]" Finalize="[object Object]" MemberwiseClone="[object Object]" test_attribute="This is a test attribute" toJSON="function toJSON() { [native code] }">example.domain.com</a></p>

我通过启用 V8ScriptEngine.SuppressInstanceMethodEnumeration 属性部分解决了这个问题,如下所示:

Using engine As New V8ScriptEngine("linkify_engine", V8ScriptEngineFlags.DisableGlobalMembers)
    engine.SuppressInstanceMethodEnumeration = True
    ' etc...
End Using

但是,输出中仍然存在反射函数和其他垃圾,我不知道如何摆脱它:toJSON

<p>Domain: <a href="http://example.domain.com" $test_attribute="This is a test attribute" test_attribute="This is a test attribute" toJSON="function toJSON() { [native code] }">example.domain.com</a></p>

当然,所需的输出将是这样的:

<p>Domain: <a href="http://example.domain.com" test_attribute="This is a test attribute">example.domain.com</a></p>

然后,我想知道如何抑制该反射成员以及以“$”符号开头的成员,例如 .toJSON$test_attribute

我认为也许我需要替换和调整匿名类型用法,以适应从命名空间继承或实现特定接口的限定类型和/或可能还使用特定的属性类,所有这些都是为了让 V8 引擎以正确的方式做事......但我不知道该怎么做。Microsoft.ClearScript

我试图定义一个自定义类型,我用它来重新定义(阴影或覆盖)和其他成员,然后我试图在这些重新定义的成员中应用各种属性类,以试图在 ClearScript 引擎中“隐藏”它们,但没有成功。无论如何,我不知道它来自哪里的功能。ToStringGetHashCodeEqualstoJSON

JavaScript .NET vb.net ClearScript

评论


答:

1赞 BitCortex 7/7/2023 #1

我可以用这个简化的代码重现你的问题:

Dim attributes = New With {.test_attribute = "This is a test attribute"}
Dim options = New With {.attributes = attributes}
Console.WriteLine(engine.Script.linkifyHtml("example.domain.com", options))

评论:该属性似乎是匿名类型的一部分,ClearScript 在公开它时可能做了正确的事情。另一方面,作为可枚举属性的存在可能是 ClearScript 中的一个错误。$test_attributetoJSON

建议:不要使用匿名类型,而应使用脚本对象。下面是一个创建并填充脚本对象的函数:

Private Function CreateObject(engine As V8ScriptEngine, ParamArray props() As (name As String, value As Object))
    Dim result = engine.Evaluate("({})")
    For Each prop In props
        result(prop.name) = prop.value
    Next
    CreateObject = result
End Function

您可以使用该函数来获取所需的行为:

Dim attributes = CreateObject(engine, ("test_attribute", "This is a test attribute"))
Dim options = CreateObject(engine, ("attributes", attributes))
Console.WriteLine(engine.Script.linkifyHtml("example.domain.com", options))

评论

0赞 ElektroStudios 7/8/2023
感谢您的帮助。我没有在我使用它的方法之外公开引擎,所以我尝试调整“CreateObject”函数以使用临时/新的 V8ScriptEngine 实例并返回一个 ScriptObject(“result”值),但是我注意到 ScriptObject 与临时引擎实例一起被处置。我想问你是否知道解决这个问题的办法,我的意思是,调整“CreateObject”函数以返回一个 ScriptObject(或其他类型的对象),稍后我可以在不同的 V8ScriptEngine 实例中使用。而不是将 V8ScriptEngine 作为“CreateObject”的第一个参数。
1赞 BitCortex 7/8/2023
为什么不以字典或强类型 .NET 对象的形式返回其数据?然后,您可以在调用脚本引擎之前将其转换为 JavaScript 对象。GetLinkifyOptions