将 VB CLR 函数转换为 C#

Convert VB CLR function to C#

如何将下面的 VB.net SQL CLR 函数转换为 VS SSDT SQL 项目的 C# CLR 函数?

我需要将其转换为 C#,因为看起来 built-in SSDT Project support for CLR functions is C# only?如果我能找到一种以与 VS SSDT 项目兼容并且不会破坏发布工作流程的方式使用原始 VB 的方法,那么我会接受这个答案!我发现在 SSMS 中使用 T-SQL 命令将 .dll 编译到 SQL 服务器真的很容易...但是当我将它引入我们的 SSDT 项目以合并到我们的下一个 .dacpac 版本中时, 没有任何效果!

SqlFunction(IsDeterministic:=True, IsPrecise:=True)> _
Public Shared Function RegExOptionEnumeration(ByVal IgnoreCase As SqlBoolean, _
             ByVal MultiLine As SqlBoolean, _
                           ByVal ExplicitCapture As SqlBoolean, _
                           ByVal Compiled As SqlBoolean, _
                           ByVal SingleLine As SqlBoolean, _
                           ByVal IgnorePatternWhitespace As SqlBoolean, _
                           ByVal RightToLeft As SqlBoolean, _
                           ByVal ECMAScript As SqlBoolean, _
                           ByVal CultureInvariant As SqlBoolean) _
              As SqlInt32
  Dim Result As Integer
  Result = (IIf(IgnoreCase.Value, RegexOptions.IgnoreCase, RegexOptions.None) Or _
   IIf(MultiLine.Value, RegexOptions.Multiline, RegexOptions.None) Or _
   IIf(ExplicitCapture.Value, RegexOptions.ExplicitCapture, _
                RegexOptions.None) Or _
   IIf(Compiled.Value, RegexOptions.Compiled, RegexOptions.None) Or _
   IIf(SingleLine.Value, RegexOptions.Singleline, RegexOptions.None) Or _
   IIf(IgnorePatternWhitespace.Value, RegexOptions.IgnorePatternWhitespace, _
                RegexOptions.None) Or _
   IIf(RightToLeft.Value, RegexOptions.RightToLeft, RegexOptions.None) Or _
   IIf(ECMAScript.Value, RegexOptions.ECMAScript, RegexOptions.None) Or _
   IIf(CultureInvariant.Value, RegexOptions.CultureInvariant, RegexOptions.None))
  Return (Result)

我已经尝试 运行 Class through Telerik C# Converter

Telerik 生成以下 C#:

public class RegularExpressionFunctions
    {
        // 
        // RegExOptions function
        // this is used simply to create the bitmap that is passed to the various 
        // CLR routines

        [SqlFunction(IsDeterministic = true, IsPrecise = true)]
        public static SqlInt32 RegExOptionEnumeration(SqlBoolean IgnoreCase, SqlBoolean MultiLine, SqlBoolean ExplicitCapture, SqlBoolean Compiled, SqlBoolean SingleLine, SqlBoolean IgnorePatternWhitespace, SqlBoolean RightToLeft, SqlBoolean ECMAScript, SqlBoolean CultureInvariant)
        {
            int Result;
            Result = (Interaction.IIf(IgnoreCase.Value, RegexOptions.IgnoreCase, RegexOptions.None) | Interaction.IIf(MultiLine.Value, RegexOptions.Multiline, RegexOptions.None) | Interaction.IIf(ExplicitCapture.Value, RegexOptions.ExplicitCapture, RegexOptions.None) | Interaction.IIf(Compiled.Value, RegexOptions.Compiled, RegexOptions.None) | Interaction.IIf(SingleLine.Value, RegexOptions.Singleline, RegexOptions.None) | Interaction.IIf(IgnorePatternWhitespace.Value, RegexOptions.IgnorePatternWhitespace, RegexOptions.None) | Interaction.IIf(RightToLeft.Value, RegexOptions.RightToLeft, RegexOptions.None) | Interaction.IIf(ECMAScript.Value, RegexOptions.ECMAScript, RegexOptions.None) | Interaction.IIf(CultureInvariant.Value, RegexOptions.CultureInvariant, RegexOptions.None));
            return (Result);
        }
}

Class 中的所有其他函数似乎都可以使用 Telerik 转换器进行转换。 我尝试四处搜索,似乎 IIf is similar to ternary operators。在此基础上,我尝试了以下2个示例,但均无效...

尝试 1

[SqlFunction(IsDeterministic = true, IsPrecise = true)]
    public static SqlInt32 RegExOptionEnumeration(SqlBoolean IgnoreCase, SqlBoolean MultiLine, SqlBoolean ExplicitCapture, SqlBoolean Compiled, SqlBoolean SingleLine, SqlBoolean IgnorePatternWhitespace, SqlBoolean RightToLeft, SqlBoolean ECMAScript, SqlBoolean CultureInvariant)
    {
        int Result;
        Result = 
            (IgnoreCase.Value == true ? RegexOptions.IgnoreCase : RegexOptions.None) ||
            (MultiLine.Value ? RegexOptions.Multiline : RegexOptions.None) ||
            (ExplicitCapture.Value ? RegexOptions.ExplicitCapture : RegexOptions.None) || 
            (Compiled.Value ? RegexOptions.Compiled : RegexOptions.None) || 
            (SingleLine.Value ? RegexOptions.Singleline : RegexOptions.None) || 
            (IgnorePatternWhitespace.Value ? RegexOptions.IgnorePatternWhitespace : RegexOptions.None) || 
            (RightToLeft.Value ? RegexOptions.RightToLeft : RegexOptions.None) || 
            (ECMAScript.Value ? RegexOptions.ECMAScript : RegexOptions.None) || 
            (CultureInvariant.Value ? RegexOptions.CultureInvariant : RegexOptions.None);
        return (Result);
    }

尝试 2

public static object Iif(bool cond, object left, object right)
    {
        return cond ? left : right;
    }

    [SqlFunction(IsDeterministic = true, IsPrecise = true)]
    public static SqlInt32 RegExOptionEnumeration(SqlBoolean IgnoreCase, SqlBoolean MultiLine, SqlBoolean ExplicitCapture, SqlBoolean Compiled, SqlBoolean SingleLine, SqlBoolean IgnorePatternWhitespace, SqlBoolean RightToLeft, SqlBoolean ECMAScript, SqlBoolean CultureInvariant)
    {
        int Result;
        Result = Iif(IgnoreCase.Value, RegexOptions.IgnoreCase, RegexOptions.None) || Iif(MultiLine.Value, RegexOptions.Multiline, RegexOptions.None) || Iif(ExplicitCapture.Value, RegexOptions.ExplicitCapture, RegexOptions.None) || Iif(Compiled.Value, RegexOptions.Compiled, RegexOptions.None) || Iif(SingleLine.Value, RegexOptions.Singleline, RegexOptions.None) || Iif(IgnorePatternWhitespace.Value, RegexOptions.IgnorePatternWhitespace, RegexOptions.None) || Iif(RightToLeft.Value, RegexOptions.RightToLeft, RegexOptions.None) || Iif(ECMAScript.Value, RegexOptions.ECMAScript, RegexOptions.None) || Iif(CultureInvariant.Value, RegexOptions.CultureInvariant, RegexOptions.None);
        return (Result);
    }

该函数正在使用正则表达式选项的位域构建一个 int(它们的设计方式可以将它们组合在一起)。所以我会写一个效用函数并做类似的事情:-

    static int BitIf(SqlBoolean condition, RegexOptions flag) => condition.Value ? (int) flag : 0;

    static SqlInt32 RegExOptionEnumeration(SqlBoolean IgnoreCase, SqlBoolean MultiLine, SqlBoolean ExplicitCapture, SqlBoolean Compiled, SqlBoolean SingleLine, SqlBoolean IgnorePatternWhitespace, SqlBoolean RightToLeft, SqlBoolean ECMAScript, SqlBoolean CultureInvariant)
    {
            return BitIf(IgnoreCase, RegexOptions.IgnoreCase)
            | BitIf(MultiLine, RegexOptions.Multiline)
            | BitIf(ExplicitCapture, RegexOptions.ExplicitCapture)
            | BitIf(Compiled, RegexOptions.Compiled)
            | BitIf(SingleLine, RegexOptions.Singleline)
            | BitIf(IgnorePatternWhitespace, RegexOptions.IgnorePatternWhitespace)
            | BitIf(RightToLeft, RegexOptions.RightToLeft)
            | BitIf(ECMAScript, RegexOptions.ECMAScript)
            | BitIf(CultureInvariant, RegexOptions.CultureInvariant);
    }
}

虽然链接文档页面上的措辞确实具有误导性,但并未说明 VB.NET 不受支持。您是否尝试过创建 VB.NET 项目?什么是出版的“坏”?我不使用 VB.NET 所以我没有尝试过,但在过去的 16 年里我也没有听到/看到任何人提出过这种说法(自从 SQLCLR 被引入并且人们已经主要使用 C#,但也肯定 VB.NET,并在较小程度上使用 Visual C++,有时,也不是没有一些痛苦,F#)。

but as soon as I brought it into our SSDT project to incorporate into our next .dacpac release, nothing worked!

这与编写它的初始语言有什么关系? DLL 使用相同的字节码,即使它最初是用 C# 编写的,对吧?您使用的 SQL 服务器是什么版本?这很可能是安全问题,而不是语言问题。

另外,你带入SSDT项目的“it”是什么?原始代码或程序集,因为它已经加载到 SQL 服务器?这可能是 SSDT 配置问题。

在任何一种情况下,如果您在使用 VB.NET 代码时收到错误,请先 post 检查这些错误并确认问题确实是语言问题,而不是它可能出现的许多其他问题是。你可能白白做了很多额外的工作,而这一切都是基于一个错误的假设。假设您确实收到消息编号 and/or 文本的错误,您是否查看了其中任何一个?再次请 post 回答问题,因为即使使用有效的 C# 代码,你也很可能 运行 再次遇到同样的问题。

另外,如果你想要 RegEx 函数,只需安装 SQL# (SQLsharp) 库(我写的)就可以了。免费版包含大部分 RegEx 函数,它们相当完整地表示了您可以在 .NET 中使用 RegEx 执行的操作(包括传入 RegExOptions):Match、Matches、Split、Replace、CaptureGroups、CaptureGroupCaptures 等

我找到了一种无需转换为 C# 即可使用 VB 脚本的方法

项目属性 > SQL CLR > 语言

完成后,所有标记为 CLR 的项目都可以使用 VB flavor:

SSDT DB 项目似乎可以使用 C# CLR 或 VB CLR,但不能同时使用两者(即使在 SQL 服务器中两者都可以)。