gpt4 book ai didi

c# - IBinarySerialize接口(interface)方法有什么用?

转载 作者:太空狗 更新时间:2023-10-29 17:40:11 28 4
gpt4 key购买 nike

创建自定义聚合函数时,需要指定enumeration format:

Format Enumeration is used by SqlUserDefinedTypeAttribute and SqlUserDefinedAggregateAttribute to indicate the serialization format of a user-defined type (UDT) or aggregate.



当使用 UserDefined格式时,您的类需要实现 IBinarySerialize Interface并覆盖其 readwrite方法。

我的问题是这些方法到底需要做什么?

查看 examples,我想他们应该能够读取/写入聚合结果?

例如,我试图创建连接不同数字的SQL CLR函数。在T-SQL中,我可以使用1到255个不同的数字(TINYINT值)。我需要从它们创建一个字符串(使用定界符),但还要对数字进行排序。该函数似乎可以正常工作,但是我不确定我是否已按预期覆盖了方法:
[Serializable]
[
Microsoft.SqlServer.Server.SqlUserDefinedAggregate
(
Microsoft.SqlServer.Server.Format.UserDefined,
IsInvariantToNulls = true,
IsInvariantToDuplicates = true,
IsInvariantToOrder = false,
MaxByteSize = 1024
)
]
public class ConcatenateAnswersPos : Microsoft.SqlServer.Server.IBinarySerialize
{
private List<byte> intermediateResult;

public void Init()
{
intermediateResult = new List<byte>();
}

public void Accumulate(SqlByte value)
{
intermediateResult.Add((byte)value);
}

public void Merge(ConcatenateAnswersPos other)
{
intermediateResult.AddRange(other.intermediateResult);
}

public SqlString Terminate()
{
if (intermediateResult != null)
{
intermediateResult.Sort();
return new SqlString(string.Join(";", intermediateResult));
}
else
{
return new SqlString("");
}

}

public void Read(BinaryReader r)
{
if (r == null) throw new ArgumentNullException("r");

intermediateResult = new List<byte>();
string[] answers = r.ReadString().Split(';');

foreach (string answer in answers)
{
intermediateResult.Add(Convert.ToByte(answer));
}
}

public void Write(BinaryWriter w)
{
if (w == null) throw new ArgumentNullException("w");
intermediateResult.Sort();
w.Write(string.Join(";", intermediateResult));
}
}

最佳答案

用户定义的聚合(UDA)的任何特定实例都不能保证在查询的整个生命周期中都存在。它需要具有可存储的表示形式。当您仅使用值类型时(如问题中“枚举格式”链接中所述),提供的ReadWrite方法将了解如何序列化和反序列化UDA,在这种情况下,您将使用Format.Native。但是,当您开始使用引用类型(字符串,集合,自定义类型等)时,您将需要定义如何对这些值进行序列化和反序列化,在这种情况下,您需要使用Format.UserDefined并覆盖ReadWrite方法,以便您可以控制这些操作。

需要序列化的值是将UDA的新实例恢复为序列化之前的确切状态所需的任何内容。这意味着:不要依赖Init()方法的运行(每个组运行一次​​!)或变量初始化程序(它们每个实例运行一次,并且可以将UDA重复用于多个组而无需重新创建!)。因此,即使它们与最终输出没有直接关系,也需要序列化所有基础值。

也就是说,您至少应该执行@Damien_The_Unbeliever的答案中指出的优化:

  • 不要在Write方法中进行排序。您已经在Terminate方法(适当的位置)中进行了此操作,因此重复两次是没有用的,更不用说效率很低了。
  • 存储集合的计数,然后存储各个元素

  • 除此之外:
  • 如果您说您的UDA“连接不同的数字”,如果您的意思确实是“不同的”,那么您需要检查每个数字,以查看它是否已经在列表中。我怀疑这是您的愿望,因为您已将IsInvariantToDuplicates设置为true。您都可以在Accumulate方法中执行以下操作:

    if (!intermediateResult.Contains(value.Value))
    {
    intermediateResult.Add(value.Value);
    }

    并在Merge方法中(涉及并行性时调用):

    foreach (byte _NewValue in other.intermediateResult)
    {
    if (!intermediateResult.Contains(_NewValue))
    {
    intermediateResult.Add(_NewValue);
    }
    }

    请注意,我已将(byte)value方法中的类型转换Accumulate更改为使用Value属性。所有SqlTypes(例如SqlByteSqlStringSqlInt32等)都具有Value属性,该属性返回您期望的.NET类型。这意味着不需要像许多人一样在ToString()上调用SqlString
  • 我会谨慎使用1024的MaxByteSize。考虑到在字符串(当前方法)中保存“165; 207”从技术上讲是14个字节(7个字符*每个字符2个字节),我可以通过实现@Damien的建议来部分缓解此问题。而保存计数和单个字节只有6个字节(Int32的4个字节用于存储count + 2个单个字节)。而此差异仅用于存储2个值。储存200个? !
  • 您没有指定IsNullIfEmpty属性。您需要指定它,特别是考虑到内部集合是Terminate时,您的null方法返回一个空字符串。您应该添加IsNullIfEmpty = false,因为如果您从未调用过它,则不想返回NULL
  • 无需使用Terminate方法中的额外逻辑来处理null集合。该集合在InitRead方法中进行了初始化,因此我不确定在调用null时它怎么可能成为Terminate


  • 如果要使用 Format.UserDefined创建用户定义的聚合的示例,请查看 Getting The Most Out of SQL Server 2005 UDTs and UDAs(需要免费注册)。我写的是在SQL Server 2008发行之前,它允许对8000多个字节进行序列化,因此(暂时)您可以忽略有关压缩数据以进行序列化的各个方面。

    另外,如果您想总体上了解有关SQLCLR的更多信息,我将在其中为SQL Server Central编写一系列文章: Stairway to SQLCLR(与第一篇链接文章相同的网站)。

    关于c# - IBinarySerialize接口(interface)方法有什么用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27781904/

    28 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com